https://github.com/akkartik/mu/blob/master/apps/mu.subx
    1 # The Mu computer's level-2 language, also called Mu.
    2 # http://akkartik.name/post/mu-2019-2
    3 #
    4 # To run:
    5 #   $ ./translate_subx init.linux [0-9]*.subx apps/mu.subx
    6 #   $ ./a.elf < prog.mu > prog.elf
    7 
    8 # == Goals
    9 # 1. Be memory safe. It should be impossible to corrupt the heap, or to create
   10 # a bad pointer. (Requires strong type safety.)
   11 # 2. Do as little as possible to achieve goal 1. The translator should be
   12 # implementable in machine code.
   13 #   - minimize impedance mismatch between source language and SubX target
   14 #     (e.g. programmer manages registers manually)
   15 #   - checks over syntax
   16 #     (e.g. programmer's register allocation is checked)
   17 #   - runtime checks to avoid complex static analysis
   18 #     (e.g. array indexing always checks bounds)
   19 
   20 # == Language description
   21 # A program is a sequence of function and type definitions.
   22 #
   23 # Function example:
   24 #   fn foo n: int -> result/eax: int {
   25 #     ...
   26 #   }
   27 #
   28 # Functions consist of a name, optional inputs, optional outputs and a block.
   29 #
   30 # Function inputs and outputs are variables. All variables have a type and
   31 # storage specifier. They can be placed either in memory (on the stack) or in
   32 # one of 6 named registers.
   33 #   eax ecx edx ebx esi edi
   34 # Variables in registers must be primitive 32-bit types.
   35 # Variables not explicitly placed in a register are on the stack.
   36 #
   37 # Function inputs are always passed in memory (on the stack), while outputs
   38 # are always returned in registers.
   39 #
   40 # Blocks mostly consist of statements.
   41 #
   42 # Statements mostly consist of a name, optional inputs and optional outputs.
   43 #
   44 # Statement inputs are variables or literals. Variables need to specify type
   45 # (and storage) the first time they're mentioned but not later.
   46 #
   47 # Statement outputs, like function outputs, must be variables in registers.
   48 #
   49 # Statement names must be either primitives or user-defined functions.
   50 #
   51 # Primitives can write to any register.
   52 # User-defined functions only write to hard-coded registers. Outputs of each
   53 # call must have the same registers as in the function definition.
   54 #
   55 # There are some other statement types:
   56 #   - blocks. Multiple statements surrounded by '{...}' and optionally
   57 #     prefixed with a label name and ':'
   58 #       - {
   59 #           ...
   60 #         }
   61 #       - foo: {
   62 #           ...
   63 #         }
   64 #
   65 #   - variable definitions on the stack. E.g.:
   66 #       - var foo: int
   67 #       - var bar: (array int 3)
   68 #     There's no initializer; variables are automatically initialized.
   69 #     The type of a local variable is either word-length (4 bytes) or starts with 'ref'.
   70 #
   71 #   - variables definitions in a register. E.g.:
   72 #       - var foo/eax: int <- add bar 1
   73 #     The initializer is mandatory and must be a valid instruction that writes
   74 #     a single output to the right register. In practice registers will
   75 #     usually be either initialized by primitives or copied from eax.
   76 #       - var eax: int <- foo bar quux
   77 #         var floo/ecx: int <- copy eax
   78 #
   79 # Still todo:
   80 #   global variables
   81 #   union types
   82 #
   83 # Formal types:
   84 #   A program is a linked list of functions
   85 #   A function contains:
   86 #     name: (handle array byte)
   87 #     inouts: linked list of vars  <-- 'inouts' is more precise than 'inputs'
   88 #       data: (handle var)
   89 #       next: (handle list)
   90 #     outputs: linked list of vars
   91 #       data: (handle var)
   92 #       next: (handle list)
   93 #     body: (handle block)
   94 #   A var-type contains:
   95 #     name: (handle array byte)
   96 #     type: (handle tree type-id)
   97 #
   98 #   A statement can be:
   99 #     tag 0: a block
  100 #     tag 1: a simple statement (stmt1)
  101 #     tag 2: a variable defined on the stack
  102 #     tag 3: a variable defined in a register
  103 #
  104 #   A block contains:
  105 #     tag: 0
  106 #     statements: (handle list stmt)
  107 #     name: (handle array byte) -- starting with '$'
  108 #
  109 #   A regular statement contains:
  110 #     tag: 1
  111 #     operation: (handle array byte)
  112 #     inouts: (handle list operand)
  113 #     outputs: (handle list var)
  114 #
  115 #   A variable defined on the stack contains:
  116 #     tag: 2
  117 #     name: (handle array byte)
  118 #     type: (handle tree type-id)
  119 #
  120 #   A variable defined in a register contains:
  121 #     tag: 3
  122 #     name: (handle array byte)
  123 #     type: (handle tree type-id)
  124 #     reg: (handle array byte)
  125 
  126 # == Translation: managing the stack
  127 # Now that we know what the language looks like in the large, let's think
  128 # about how translation happens from the bottom up. One crucial piece of the
  129 # puzzle is how Mu will clean up variables defined on the stack for you.
  130 #
  131 # Assume that we maintain a 'functions' list while parsing source code. And a
  132 # 'primitives' list is a global constant. Both these contain enough information
  133 # to perform type-checking on function calls or primitive statements, respectively.
  134 #
  135 # Defining variables pushes them on a stack with the current block depth and
  136 # enough information about their location (stack offset or register).
  137 # Starting a block increments the current block id.
  138 # Each statement now has enough information to emit code for it.
  139 # Ending a block is where the magic happens:
  140 #   pop all variables at the current block depth
  141 #   emit code to restore all register variables introduced at the current depth
  142 #   emit code to clean up all stack variables at the current depth (just increment esp)
  143 #   decrement the current block depth
  144 #
  145 # Formal types:
  146 #   live-vars: stack of vars
  147 #   var:
  148 #     name: (handle array byte)
  149 #     type: (handle tree type-id)
  150 #     block: int
  151 #     stack-offset: int  (added to ebp)
  152 #     register: (handle array byte)
  153 #       either usual register names
  154 #       or '*' to indicate any register
  155 #   At most one of stack-offset or register-index must be non-zero.
  156 #   A register of '*' designates a variable _template_. Only legal in formal
  157 #   parameters for primitives.
  158 
  159 # == Translating a single function call
  160 # This one's easy. Assuming we've already checked things, we just drop the
  161 # outputs (which use hard-coded registers) and emit inputs in a standard format.
  162 #
  163 # out1, out2, out3, ... <- name inout1, inout2, inout3, ...
  164 # =>
  165 # (name inout1 inout2 inout3)
  166 #
  167 # Formal types:
  168 #   functions: linked list of info
  169 #     name: (handle array byte)
  170 #     inouts: linked list of vars
  171 #     outputs: linked list of vars
  172 #     body: block (linked list of statements)
  173 
  174 # == Translating a single primitive instruction
  175 # A second crucial piece of the puzzle is how Mu converts fairly regular
  176 # primitives with their uniform syntax to SubX instructions with their gnarly
  177 # x86 details.
  178 #
  179 # Mu instructions have inputs and outputs. Primitives can have up to 2 of
  180 # them.
  181 # SubX instructions have rm32 and r32 operands.
  182 # The translation between them covers almost all the possibilities.
  183 #   Instructions with 1 inout may turn into ones with 1 rm32
  184 #     (e.g. incrementing a var on the stack)
  185 #   Instructions with 1 output may turn into ones with 1 rm32
  186 #     (e.g. incrementing a var in a register)
  187 #   1 inout and 1 output may turn into 1 rm32 and 1 r32
  188 #     (e.g. adding a var to a reg)
  189 #   2 inouts may turn into 1 rm32 and 1 r32
  190 #     (e.g. adding a reg to a var)
  191 #   1 inout and 1 literal may turn into 1 rm32 and 1 imm32
  192 #     (e.g. adding a constant to a var)
  193 #   1 output and 1 literal may turn into 1 rm32 and 1 imm32
  194 #     (e.g. adding a constant to a reg)
  195 #   2 outputs to hardcoded registers and 1 inout may turn into 1 rm32
  196 #     (special-case: divide edx:eax by a var or reg)
  197 # Observations:
  198 #   We always emit rm32. It may be the first inout or the first output.
  199 #   We may emit r32 or imm32 or neither.
  200 #   When we emit r32 it may come from first inout or second inout or first output.
  201 #
  202 # Accordingly, the formal data structure for a primitive looks like this:
  203 #   primitives: linked list of info
  204 #     name: (handle array byte)
  205 #     mu-inouts: linked list of vars to check
  206 #     mu-outputs: linked list of vars to check; at most a singleton
  207 #     subx-name: (handle array byte)
  208 #     subx-rm32: enum arg-location
  209 #     subx-r32: enum arg-location
  210 #     subx-imm32: enum arg-location
  211 #     subx-disp32: enum arg-location
  212 #     output-is-write-only: boolean
  213 #   arg-location: enum
  214 #     0 means none
  215 #     1 means first inout
  216 #     2 means second inout
  217 #     3 means first output
  218 
  219 # == Translating a block
  220 # Emit block name if necessary
  221 # Emit '{'
  222 # When you encounter a statement, emit it as above
  223 # When you encounter a variable declaration
  224 #   emit any code needed for it (bzeros)
  225 #   push it on the var stack
  226 #   update register dict if necessary
  227 # When you encounter '}'
  228 #   While popping variables off the var stack until block id changes
  229 #     Emit code needed to clean up the stack
  230 #       either increment esp
  231 #       or pop into appropriate register
  232 
  233 # The rest is straightforward.
  234 
  235 == data
  236 
  237 Program:
  238 _Program-functions:  # (handle function)
  239   0/imm32
  240 _Program-functions->payload:
  241   0/imm32
  242 _Program-types:  # (handle typeinfo)
  243   0/imm32
  244 _Program-types->payload:
  245   0/imm32
  246 
  247 # Some constants for simulating the data structures described above.
  248 # Many constants here come with a type in a comment.
  249 #
  250 # Sometimes the type is of the value at that offset for the given type. For
  251 # example, if you start at a function record and move forward Function-inouts
  252 # bytes, you'll find a (handle list var).
  253 #
  254 # At other times, the type is of the constant itself. For example, the type of
  255 # the constant Function-size is (addr int). To get the size of a function,
  256 # look in *Function-size.
  257 
  258 Function-name:  # (handle array byte)
  259   0/imm32
  260 Function-inouts:  # (handle list var)
  261   8/imm32
  262 Function-outputs:  # (handle list var)
  263   0x10/imm32
  264 Function-body:  # (handle block)
  265   0x18/imm32
  266 Function-next:  # (handle function)
  267   0x20/imm32
  268 Function-size:  # (addr int)
  269   0x28/imm32/40
  270 
  271 Primitive-name:  # (handle array byte)
  272   0/imm32
  273 Primitive-inouts:  # (handle list var)
  274   8/imm32
  275 Primitive-outputs:  # (handle list var)
  276   0x10/imm32
  277 Primitive-subx-name:  # (handle array byte)
  278   0x18/imm32
  279 Primitive-subx-rm32:  # enum arg-location
  280   0x20/imm32
  281 Primitive-subx-r32:  # enum arg-location
  282   0x24/imm32
  283 Primitive-subx-imm32:  # enum arg-location
  284   0x28/imm32
  285 Primitive-subx-disp32:  # enum arg-location  -- only for branches
  286   0x2c/imm32
  287 Primitive-output-is-write-only:  # boolean
  288   0x30/imm32
  289 Primitive-next:  # (handle function)
  290   0x34/imm32
  291 Primitive-size:  # (addr int)
  292   0x3c/imm32/60
  293 
  294 Stmt-tag:  # int
  295   0/imm32
  296 
  297 Block-stmts:  # (handle list stmt)
  298   4/imm32
  299 Block-var:  # (handle var)
  300   0xc/imm32
  301 
  302 Stmt1-operation:  # (handle array byte)
  303   4/imm32
  304 Stmt1-inouts:  # (handle stmt-var)
  305   0xc/imm32
  306 Stmt1-outputs:  # (handle stmt-var)
  307   0x14/imm32
  308 
  309 Vardef-var:  # (handle var)
  310   4/imm32
  311 
  312 Regvardef-operation:  # (handle array byte)
  313   4/imm32
  314 Regvardef-inouts:  # (handle stmt-var)
  315   0xc/imm32
  316 Regvardef-outputs:  # (handle stmt-var)  # will have exactly one element
  317   0x14/imm32
  318 
  319 Stmt-size:  # (addr int)
  320   0x1c/imm32
  321 
  322 Var-name:  # (handle array byte)
  323   0/imm32
  324 Var-type:  # (handle tree type-id)
  325   8/imm32
  326 Var-block-depth:  # int -- not available until code-generation time
  327   0x10/imm32
  328 Var-offset:  # int -- not available until code-generation time
  329   0x14/imm32
  330 Var-register:  # (handle array byte) -- name of a register
  331   0x18/imm32
  332 Var-size:  # (addr int)
  333   0x20/imm32
  334 
  335 List-value:  # (handle _)
  336   0/imm32
  337 List-next:  # (handle list _)
  338   8/imm32
  339 List-size:  # (addr int)
  340   0x10/imm32
  341 
  342 # A stmt-var is like a list of vars with call-site specific metadata
  343 Stmt-var-value:  # (handle var)
  344   0/imm32
  345 Stmt-var-next:  # (handle stmt-var)
  346   8/imm32
  347 Stmt-var-is-deref:  # boolean
  348   0x10/imm32
  349 Stmt-var-size:  # (addr int)
  350   0x14/imm32
  351 
  352 # A live-var is a var augmented with information needed for tracking live
  353 # variables.
  354 Live-var-value:  # (handle var)
  355   0/imm32
  356 Live-var-register-spilled:  # boolean; only used if value is in a register, and only during code-gen
  357   8/imm32
  358 Live-var-size:  # (addr int)
  359   0xc/imm32
  360 
  361 # Types are expressed as trees (s-expressions) of type-ids (ints).
  362 
  363 Tree-is-atom:  # boolean
  364   0/imm32
  365 # if left-is-atom?
  366 Tree-value:  # type-id
  367   4/imm32
  368 # unless left-is-atom?
  369 Tree-left:  # (addr tree type-id)
  370   4/imm32
  371 Tree-right:  # (addr tree type-id)
  372   0xc/imm32
  373 #
  374 Tree-size:  # (addr int)
  375   0x14/imm32
  376 
  377 # Types
  378 
  379 # TODO: Turn this data structure into valid Mu, with (fake) handles rather than addrs.
  380 Type-id:  # (stream (addr array byte))
  381   0/imm32/write  # initialized later from Primitive-type-ids
  382   0/imm32/read
  383   0x100/imm32/size
  384   # data
  385   "literal"/imm32  # 0: value is just the name
  386   "int"/imm32  # 1
  387   "addr"/imm32  # 2
  388   "array"/imm32  # 3
  389   "handle"/imm32  # 4
  390   "boolean"/imm32  # 5
  391   "constant"/imm32  # 6: like a literal, but value is an int in Var-offset
  392   "offset"/imm32  # 7: (offset T) is guaranteed to be a 32-bit multiple of size-of(T)
  393   # 0x20
  394   "byte"/imm32  # 8
  395           0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  396   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  397   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  398   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  399   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  400   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  401   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  402 
  403 Primitive-type-ids:  # (addr int)
  404   0x24
  405 
  406 # == Type definitions
  407 # Program->types contains some typeinfo for each type definition.
  408 # Types contain vars with types, but can't specify registers.
  409 Typeinfo-id:  # type-id
  410   0/imm32
  411 Typeinfo-fields:  # (handle table (handle array byte) (handle typeinfo-entry))
  412   4/imm32
  413 # Total size must be >= 0
  414 # During parsing it may take on two additional values:
  415 #   -2: not yet initialized
  416 #   -1: in process of being computed
  417 # See populate-mu-type-sizes for details.
  418 Typeinfo-total-size-in-bytes:  # int
  419   0xc/imm32
  420 Typeinfo-next:  # (handle typeinfo)
  421   0x10/imm32
  422 Typeinfo-size:  # (addr int)
  423   0x18/imm32
  424 
  425 # Each entry in the typeinfo->fields table has a pointer to a string and a
  426 # pointer to a typeinfo-entry.
  427 Typeinfo-fields-row-size:  # (addr int)
  428   0x10/imm32
  429 
  430 # typeinfo-entry objects have information about a field in a single record type
  431 #
  432 # each field of a type is represented using two var's:
  433 #   1. the input var: expected type of the field; convenient for creating using parse-var-with-type
  434 #   2. the output var: a constant containing the byte offset; convenient for code-generation
  435 # computing the output happens after parsing; in the meantime we preserve the
  436 # order of fields in the 'index' field.
  437 Typeinfo-entry-input-var:  # (handle var)
  438   0/imm32
  439 Typeinfo-entry-index:  # int
  440   8/imm32
  441 Typeinfo-entry-output-var:  # (handle var)
  442   0xc/imm32
  443 Typeinfo-entry-size:  # (addr int)
  444   0x14/imm32
  445 
  446 == code
  447 
  448 Entry:
  449     # . prologue
  450     89/<- %ebp 4/r32/esp
  451     (new-segment *Heap-size Heap)
  452     # if (argv[1] == "test') run-tests()
  453     {
  454       # if (argc <= 1) break
  455       81 7/subop/compare *ebp 1/imm32
  456       7e/jump-if-<= break/disp8
  457       # if (argv[1] != "test") break
  458       (kernel-string-equal? *(ebp+8) "test")  # => eax
  459       3d/compare-eax-and 0/imm32/false
  460       74/jump-if-= break/disp8
  461       #
  462       (run-tests)
  463       # syscall(exit, *Num-test-failures)
  464       8b/-> *Num-test-failures 3/r32/ebx
  465       eb/jump $mu-main:end/disp8
  466     }
  467     # otherwise convert Stdin
  468     (convert-mu Stdin Stdout Stderr 0)
  469     (flush Stdout)
  470     # syscall(exit, 0)
  471     bb/copy-to-ebx 0/imm32
  472 $mu-main:end:
  473     e8/call syscall_exit/disp32
  474 
  475 convert-mu:  # in: (addr buffered-file), out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
  476     # . prologue
  477     55/push-ebp
  478     89/<- %ebp 4/r32/esp
  479     # . save registers
  480     50/push-eax
  481     # initialize global data structures
  482     c7 0/subop/copy *Next-block-index 1/imm32
  483     8b/-> *Primitive-type-ids 0/r32/eax
  484     89/<- *Type-id 0/r32/eax  # stream-write
  485     c7 0/subop/copy *_Program-functions 0/imm32
  486     c7 0/subop/copy *_Program-functions->payload 0/imm32
  487     c7 0/subop/copy *_Program-types 0/imm32
  488     c7 0/subop/copy *_Program-types->payload 0/imm32
  489     #
  490     (parse-mu *(ebp+8) *(ebp+0x10) *(ebp+0x14))
  491     (populate-mu-type-sizes *(ebp+0x10) *(ebp+0x14))
  492 #?     (dump-typeinfos "=== typeinfos\n")
  493     (check-mu-types *(ebp+0x10) *(ebp+0x14))
  494     (emit-subx *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
  495 $convert-mu:end:
  496     # . restore registers
  497     58/pop-to-eax
  498     # . epilogue
  499     89/<- %esp 5/r32/ebp
  500     5d/pop-to-ebp
  501     c3/return
  502 
  503 test-convert-empty-input:
  504     # empty input => empty output
  505     # . prologue
  506     55/push-ebp
  507     89/<- %ebp 4/r32/esp
  508     # setup
  509     (clear-stream _test-input-stream)
  510     (clear-stream $_test-input-buffered-file->buffer)
  511     (clear-stream _test-output-stream)
  512     (clear-stream $_test-output-buffered-file->buffer)
  513     #
  514     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  515     (flush _test-output-buffered-file)
  516     (check-stream-equal _test-output-stream "" "F - test-convert-empty-input")
  517     # . epilogue
  518     89/<- %esp 5/r32/ebp
  519     5d/pop-to-ebp
  520     c3/return
  521 
  522 test-convert-function-skeleton:
  523     # . prologue
  524     55/push-ebp
  525     89/<- %ebp 4/r32/esp
  526     # setup
  527     (clear-stream _test-input-stream)
  528     (clear-stream $_test-input-buffered-file->buffer)
  529     (clear-stream _test-output-stream)
  530     (clear-stream $_test-output-buffered-file->buffer)
  531     #
  532     (write _test-input-stream "fn foo {\n")
  533     (write _test-input-stream "}\n")
  534     # convert
  535     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  536     (flush _test-output-buffered-file)
  537 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  543     # check output
  544     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-skeleton/0")
  545     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-skeleton/1")
  546     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-skeleton/2")
  547     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-skeleton/3")
  548     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-skeleton/4")
  549     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-skeleton/5")
  550     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-skeleton/6")
  551     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-skeleton/7")
  552     # . epilogue
  553     89/<- %esp 5/r32/ebp
  554     5d/pop-to-ebp
  555     c3/return
  556 
  557 test-convert-multiple-function-skeletons:
  558     # . prologue
  559     55/push-ebp
  560     89/<- %ebp 4/r32/esp
  561     # setup
  562     (clear-stream _test-input-stream)
  563     (clear-stream $_test-input-buffered-file->buffer)
  564     (clear-stream _test-output-stream)
  565     (clear-stream $_test-output-buffered-file->buffer)
  566     #
  567     (write _test-input-stream "fn foo {\n")
  568     (write _test-input-stream "}\n")
  569     (write _test-input-stream "fn bar {\n")
  570     (write _test-input-stream "}\n")
  571     # convert
  572     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  573     (flush _test-output-buffered-file)
  574 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  580     # check first function
  581     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-multiple-function-skeletons/0")
  582     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/1")
  583     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/2")
  584     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/3")
  585     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/4")
  586     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/5")
  587     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/6")
  588     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/7")
  589     # check second function
  590     (check-next-stream-line-equal _test-output-stream "bar:"                    "F - test-convert-multiple-function-skeletons/10")
  591     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/11")
  592     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/12")
  593     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/13")
  594     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/14")
  595     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/15")
  596     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/16")
  597     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/17")
  598     # . epilogue
  599     89/<- %esp 5/r32/ebp
  600     5d/pop-to-ebp
  601     c3/return
  602 
  603 test-convert-function-with-arg:
  604     # . prologue
  605     55/push-ebp
  606     89/<- %ebp 4/r32/esp
  607     # setup
  608     (clear-stream _test-input-stream)
  609     (clear-stream $_test-input-buffered-file->buffer)
  610     (clear-stream _test-output-stream)
  611     (clear-stream $_test-output-buffered-file->buffer)
  612     #
  613     (write _test-input-stream "fn foo n: int {\n")
  614     (write _test-input-stream "}\n")
  615     # convert
  616     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  617     (flush _test-output-buffered-file)
  618 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  624     # check output
  625     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg/0")
  626     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg/1")
  627     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg/2")
  628     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg/3")
  629     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg/4")
  630     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg/5")
  631     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg/6")
  632     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg/7")
  633     # . epilogue
  634     89/<- %esp 5/r32/ebp
  635     5d/pop-to-ebp
  636     c3/return
  637 
  638 test-convert-function-with-arg-and-body:
  639     # . prologue
  640     55/push-ebp
  641     89/<- %ebp 4/r32/esp
  642     # setup
  643     (clear-stream _test-input-stream)
  644     (clear-stream $_test-input-buffered-file->buffer)
  645     (clear-stream _test-output-stream)
  646     (clear-stream $_test-output-buffered-file->buffer)
  647     #
  648     (write _test-input-stream "fn foo n: int {\n")
  649     (write _test-input-stream "  increment n\n")
  650     (write _test-input-stream "}\n")
  651     # convert
  652     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  653     (flush _test-output-buffered-file)
  654 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  660     # check output
  661     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg-and-body/0")
  662     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg-and-body/1")
  663     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg-and-body/2")
  664     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg-and-body/3")
  665     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-arg-and-body/4")
  666     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-arg-and-body/5")
  667     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-arg-and-body/6")
  668     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-arg-and-body/7")
  669     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-arg-and-body/8")
  670     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg-and-body/9")
  671     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg-and-body/10")
  672     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg-and-body/11")
  673     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg-and-body/12")
  674     # . epilogue
  675     89/<- %esp 5/r32/ebp
  676     5d/pop-to-ebp
  677     c3/return
  678 
  679 test-convert-function-distinguishes-args:
  680     # . prologue
  681     55/push-ebp
  682     89/<- %ebp 4/r32/esp
  683     # setup
  684     (clear-stream _test-input-stream)
  685     (clear-stream $_test-input-buffered-file->buffer)
  686     (clear-stream _test-output-stream)
  687     (clear-stream $_test-output-buffered-file->buffer)
  688     #
  689     (write _test-input-stream "fn foo a: int, b: int {\n")
  690     (write _test-input-stream "  increment b\n")
  691     (write _test-input-stream "}\n")
  692     # convert
  693     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  694     (flush _test-output-buffered-file)
  695 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  701     # check output
  702     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-distinguishes-args/0")
  703     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-distinguishes-args/1")
  704     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-distinguishes-args/2")
  705     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-distinguishes-args/3")
  706     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-distinguishes-args/4")
  707     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-distinguishes-args/5")
  708     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x0000000c)"  "F - test-convert-function-distinguishes-args/6")
  709     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-distinguishes-args/7")
  710     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-distinguishes-args/8")
  711     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-distinguishes-args/9")
  712     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-distinguishes-args/10")
  713     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-distinguishes-args/11")
  714     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-distinguishes-args/12")
  715     # . epilogue
  716     89/<- %esp 5/r32/ebp
  717     5d/pop-to-ebp
  718     c3/return
  719 
  720 test-convert-function-returns-result:
  721     # . prologue
  722     55/push-ebp
  723     89/<- %ebp 4/r32/esp
  724     # setup
  725     (clear-stream _test-input-stream)
  726     (clear-stream $_test-input-buffered-file->buffer)
  727     (clear-stream _test-output-stream)
  728     (clear-stream $_test-output-buffered-file->buffer)
  729     #
  730     (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n")
  731     (write _test-input-stream "  result <- copy a\n")
  732     (write _test-input-stream "  result <- increment\n")
  733     (write _test-input-stream "}\n")
  734     # convert
  735     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  736     (flush _test-output-buffered-file)
  737 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  743     # check output
  744     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-returns-result/0")
  745     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-returns-result/1")
  746     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-returns-result/2")
  747     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-returns-result/3")
  748     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-returns-result/4")
  749     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-returns-result/5")
  750     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-returns-result/6")
  751     (check-next-stream-line-equal _test-output-stream "    40/increment-eax"    "F - test-convert-function-returns-result/7")
  752     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-returns-result/8")
  753     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-returns-result/9")
  754     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-returns-result/10")
  755     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-returns-result/11")
  756     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-returns-result/12")
  757     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-returns-result/13")
  758     # . epilogue
  759     89/<- %esp 5/r32/ebp
  760     5d/pop-to-ebp
  761     c3/return
  762 
  763 test-convert-function-with-literal-arg:
  764     # . prologue
  765     55/push-ebp
  766     89/<- %ebp 4/r32/esp
  767     # setup
  768     (clear-stream _test-input-stream)
  769     (clear-stream $_test-input-buffered-file->buffer)
  770     (clear-stream _test-output-stream)
  771     (clear-stream $_test-output-buffered-file->buffer)
  772     #
  773     (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n")
  774     (write _test-input-stream "  result <- copy a\n")
  775     (write _test-input-stream "  result <- add 1\n")
  776     (write _test-input-stream "}\n")
  777     # convert
  778     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  779     (flush _test-output-buffered-file)
  780 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  786     # check output
  787     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg/0")
  788     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg/1")
  789     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg/2")
  790     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg/3")
  791     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg/4")
  792     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg/5")
  793     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-with-literal-arg/6")
  794     (check-next-stream-line-equal _test-output-stream "    05/add-to-eax 1/imm32"  "F - test-convert-function-with-literal-arg/7")
  795     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg/8")
  796     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg/9")
  797     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg/10")
  798     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg/11")
  799     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg/12")
  800     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg/13")
  801     # . epilogue
  802     89/<- %esp 5/r32/ebp
  803     5d/pop-to-ebp
  804     c3/return
  805 
  806 test-convert-function-with-literal-arg-2:
  807     # . prologue
  808     55/push-ebp
  809     89/<- %ebp 4/r32/esp
  810     # setup
  811     (clear-stream _test-input-stream)
  812     (clear-stream $_test-input-buffered-file->buffer)
  813     (clear-stream _test-output-stream)
  814     (clear-stream $_test-output-buffered-file->buffer)
  815     #
  816     (write _test-input-stream "fn foo a: int, b: int -> result/ebx: int {\n")
  817     (write _test-input-stream "  result <- copy a\n")
  818     (write _test-input-stream "  result <- add 1\n")
  819     (write _test-input-stream "}\n")
  820     # convert
  821     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  822     (flush _test-output-buffered-file)
  823 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  829     # check output
  830     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg-2/0")
  831     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg-2/1")
  832     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg-2/2")
  833     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg-2/3")
  834     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg-2/4")
  835     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg-2/5")
  836     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-with-literal-arg-2/6")
  837     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %ebx 1/imm32"  "F - test-convert-function-with-literal-arg-2/7")
  838     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg-2/8")
  839     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg-2/9")
  840     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg-2/10")
  841     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg-2/11")
  842     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg-2/12")
  843     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg-2/13")
  844     # . epilogue
  845     89/<- %esp 5/r32/ebp
  846     5d/pop-to-ebp
  847     c3/return
  848 
  849 # HERE
  850 test-convert-function-call-with-literal-arg:
  851     # . prologue
  852     55/push-ebp
  853     89/<- %ebp 4/r32/esp
  854     # setup
  855     (clear-stream _test-input-stream)
  856     (clear-stream $_test-input-buffered-file->buffer)
  857     (clear-stream _test-output-stream)
  858     (clear-stream $_test-output-buffered-file->buffer)
  859     #
  860     (write _test-input-stream "fn main -> result/ebx: int {\n")
  861     (write _test-input-stream "  result <- do-add 3 4\n")
  862     (write _test-input-stream "}\n")
  863     (write _test-input-stream "fn do-add a: int, b: int -> result/ebx: int {\n")
  864     (write _test-input-stream "  result <- copy a\n")
  865     (write _test-input-stream "  result <- add b\n")
  866     (write _test-input-stream "}\n")
  867     # convert
  868     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  869     (flush _test-output-buffered-file)
  870 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  876     # check output
  877     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call-with-literal-arg/0")
  878     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/1")
  879     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/2")
  880     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/3")
  881     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/4")
  882     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call-with-literal-arg/5")
  883     (check-next-stream-line-equal _test-output-stream "    (do-add 3 4)"        "F - test-convert-function-call-with-literal-arg/6")
  884     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/7")
  885     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-literal-arg/8")
  886     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/9")
  887     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/10")
  888     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/11")
  889     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/12")
  890     (check-next-stream-line-equal _test-output-stream "do-add:"                 "F - test-convert-function-call-with-literal-arg/13")
  891     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/14")
  892     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/15")
  893     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/16")
  894     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/17")
  895     (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:loop:"  "F - test-convert-function-call-with-literal-arg/18")
  896     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-call-with-literal-arg/19")
  897     (check-next-stream-line-equal _test-output-stream "    03/add *(ebp+0x0000000c) 0x00000003/r32"  "F - test-convert-function-call-with-literal-arg/20")
  898     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/21")
  899     (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:break:"  "F - test-convert-function-call-with-literal-arg/22")
  900     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/23")
  901     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/24")
  902     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/25")
  903     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/26")
  904     # . epilogue
  905     89/<- %esp 5/r32/ebp
  906     5d/pop-to-ebp
  907     c3/return
  908 
  909 test-convert-function-with-local-var-in-mem:
  910     # . prologue
  911     55/push-ebp
  912     89/<- %ebp 4/r32/esp
  913     # setup
  914     (clear-stream _test-input-stream)
  915     (clear-stream $_test-input-buffered-file->buffer)
  916     (clear-stream _test-output-stream)
  917     (clear-stream $_test-output-buffered-file->buffer)
  918     #
  919     (write _test-input-stream "fn foo {\n")
  920     (write _test-input-stream "  var x: int\n")
  921     (write _test-input-stream "  increment x\n")
  922     (write _test-input-stream "}\n")
  923     # convert
  924     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  925     (flush _test-output-buffered-file)
  926 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  932     # check output
  933     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-mem/0")
  934     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-mem/1")
  935     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-mem/2")
  936     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-mem/3")
  937     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-mem/4")
  938     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-mem/5")
  939     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-in-mem/6")
  940     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-mem/7")
  941     (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")
  942     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-mem/9")
  943     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-mem/10")
  944     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-mem/11")
  945     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-mem/12")
  946     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-mem/13")
  947     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-mem/14")
  948     # . epilogue
  949     89/<- %esp 5/r32/ebp
  950     5d/pop-to-ebp
  951     c3/return
  952 
  953 test-local-var-in-mem-has-no-initializer:
  954     # . prologue
  955     55/push-ebp
  956     89/<- %ebp 4/r32/esp
  957     # setup
  958     (clear-stream _test-input-stream)
  959     (clear-stream $_test-input-buffered-file->buffer)
  960     (clear-stream _test-output-stream)
  961     (clear-stream $_test-output-buffered-file->buffer)
  962     (clear-stream _test-error-stream)
  963     (clear-stream $_test-error-buffered-file->buffer)
  964     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
  965     68/push 0/imm32
  966     68/push 0/imm32
  967     89/<- %edx 4/r32/esp
  968     (tailor-exit-descriptor %edx 0x10)
  969     #
  970     (write _test-input-stream "fn foo {\n")
  971     (write _test-input-stream "  var x: int <- copy 0\n")
  972     (write _test-input-stream "  increment x\n")
  973     (write _test-input-stream "}\n")
  974     # convert
  975     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
  976     # registers except esp clobbered at this point
  977     # restore ed
  978     89/<- %edx 4/r32/esp
  979     (flush _test-output-buffered-file)
  980     (flush _test-error-buffered-file)
  981 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
  987     # check output
  988     (check-stream-equal _test-output-stream  ""  "F - test-var-in-mem-has-no-initializer: output should be empty")
  989     (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")
  990     # check that stop(1) was called
  991     (check-ints-equal *(edx+4) 2 "F - test-var-in-mem-has-no-initializer: exit status")
  992     # don't restore from ebp
  993     81 0/subop/add %esp 8/imm32
  994     # . epilogue
  995     5d/pop-to-ebp
  996     c3/return
  997 
  998 test-convert-function-with-local-var-with-compound-type-in-mem:
  999     # . prologue
 1000     55/push-ebp
 1001     89/<- %ebp 4/r32/esp
 1002     # setup
 1003     (clear-stream _test-input-stream)
 1004     (clear-stream $_test-input-buffered-file->buffer)
 1005     (clear-stream _test-output-stream)
 1006     (clear-stream $_test-output-buffered-file->buffer)
 1007     #
 1008     (write _test-input-stream "fn foo {\n")
 1009     (write _test-input-stream "  var x: (addr int)\n")
 1010     (write _test-input-stream "  copy-to x, 0\n")
 1011     (write _test-input-stream "}\n")
 1012     # convert
 1013     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1014     (flush _test-output-buffered-file)
 1015 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1021     # check output
 1022     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-compound-type-in-mem/0")
 1023     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/1")
 1024     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-compound-type-in-mem/2")
 1025     (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")
 1026     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/4")
 1027     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-compound-type-in-mem/5")
 1028     (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")
 1029     (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")
 1030     (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")
 1031     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/9")
 1032     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/10")
 1033     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/11")
 1034     (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")
 1035     (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")
 1036     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-compound-type-in-mem/14")
 1037     # . epilogue
 1038     89/<- %esp 5/r32/ebp
 1039     5d/pop-to-ebp
 1040     c3/return
 1041 
 1042 test-convert-function-with-local-var-in-reg:
 1043     # . prologue
 1044     55/push-ebp
 1045     89/<- %ebp 4/r32/esp
 1046     # setup
 1047     (clear-stream _test-input-stream)
 1048     (clear-stream $_test-input-buffered-file->buffer)
 1049     (clear-stream _test-output-stream)
 1050     (clear-stream $_test-output-buffered-file->buffer)
 1051     #
 1052     (write _test-input-stream "fn foo {\n")
 1053     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1054     (write _test-input-stream "  x <- increment\n")
 1055     (write _test-input-stream "}\n")
 1056     # convert
 1057     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1058     (flush _test-output-buffered-file)
 1059 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1065     # check output
 1066     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-reg/0")
 1067     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-reg/1")
 1068     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-reg/2")
 1069     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-reg/3")
 1070     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-reg/4")
 1071     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-reg/5")
 1072     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-in-reg/6")
 1073     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-convert-function-with-local-var-in-reg/7")
 1074     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-local-var-in-reg/8")
 1075     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-in-reg/9")
 1076     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-reg/10")
 1077     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-reg/11")
 1078     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-reg/12")
 1079     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-reg/13")
 1080     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-reg/14")
 1081     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-reg/15")
 1082     # . epilogue
 1083     89/<- %esp 5/r32/ebp
 1084     5d/pop-to-ebp
 1085     c3/return
 1086 
 1087 test-convert-function-with-second-local-var-in-same-reg:
 1088     # . prologue
 1089     55/push-ebp
 1090     89/<- %ebp 4/r32/esp
 1091     # setup
 1092     (clear-stream _test-input-stream)
 1093     (clear-stream $_test-input-buffered-file->buffer)
 1094     (clear-stream _test-output-stream)
 1095     (clear-stream $_test-output-buffered-file->buffer)
 1096     #
 1097     (write _test-input-stream "fn foo {\n")
 1098     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1099     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1100     (write _test-input-stream "  y <- increment\n")
 1101     (write _test-input-stream "}\n")
 1102     # convert
 1103     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1104     (flush _test-output-buffered-file)
 1105 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1111     # check output
 1112     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-second-local-var-in-same-reg/0")
 1113     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-second-local-var-in-same-reg/1")
 1114     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-second-local-var-in-same-reg/2")
 1115     (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")
 1116     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-second-local-var-in-same-reg/4")
 1117     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-second-local-var-in-same-reg/5")
 1118     (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")
 1119     (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")
 1120     (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")
 1121     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-second-local-var-in-same-reg/9")
 1122     (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")
 1123     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-second-local-var-in-same-reg/11")
 1124     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-second-local-var-in-same-reg/12")
 1125     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-second-local-var-in-same-reg/13")
 1126     (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")
 1127     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-second-local-var-in-same-reg/15")
 1128     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-second-local-var-in-same-reg/16")
 1129     # . epilogue
 1130     89/<- %esp 5/r32/ebp
 1131     5d/pop-to-ebp
 1132     c3/return
 1133 
 1134 test-read-clobbered-reg-var:
 1135     # . prologue
 1136     55/push-ebp
 1137     89/<- %ebp 4/r32/esp
 1138     # setup
 1139     (clear-stream _test-input-stream)
 1140     (clear-stream $_test-input-buffered-file->buffer)
 1141     (clear-stream _test-output-stream)
 1142     (clear-stream $_test-output-buffered-file->buffer)
 1143     (clear-stream _test-error-stream)
 1144     (clear-stream $_test-error-buffered-file->buffer)
 1145     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)  # bytes of args in call to convert-mu
 1146     68/push 0/imm32
 1147     68/push 0/imm32
 1148     89/<- %edx 4/r32/esp
 1149     (tailor-exit-descriptor %edx 0x10)
 1150     #
 1151     (write _test-input-stream "fn foo {\n")
 1152     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1153     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1154     (write _test-input-stream "  x <- increment\n")
 1155     (write _test-input-stream "}\n")
 1156     # convert
 1157     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1158     # registers except esp clobbered at this point
 1159     # restore ed
 1160     89/<- %edx 4/r32/esp
 1161     (flush _test-output-buffered-file)
 1162     (flush _test-error-buffered-file)
 1163 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1169     # check output
 1170     (check-stream-equal _test-output-stream  ""  "F - test-read-clobbered-reg-var: output should be empty")
 1171     (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")
 1172     # check that stop(1) was called
 1173     (check-ints-equal *(edx+4) 2 "F - test-read-clobbered-reg-var: exit status")
 1174     # don't restore from ebp
 1175     81 0/subop/add %esp 8/imm32
 1176     # . epilogue
 1177     5d/pop-to-ebp
 1178     c3/return
 1179 
 1180 test-convert-function-call:
 1181     # . prologue
 1182     55/push-ebp
 1183     89/<- %ebp 4/r32/esp
 1184     # setup
 1185     (clear-stream _test-input-stream)
 1186     (clear-stream $_test-input-buffered-file->buffer)
 1187     (clear-stream _test-output-stream)
 1188     (clear-stream $_test-output-buffered-file->buffer)
 1189     #
 1190     (write _test-input-stream "fn main -> result/ebx: int {\n")
 1191     (write _test-input-stream "  result <- foo\n")
 1192     (write _test-input-stream "}\n")
 1193     (write _test-input-stream "fn foo -> result/ebx: int {\n")
 1194     (write _test-input-stream "  result <- copy 3\n")
 1195     (write _test-input-stream "}\n")
 1196     # convert
 1197     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1198     (flush _test-output-buffered-file)
 1199 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1205     # check output
 1206     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call/0")
 1207     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call/1")
 1208     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call/2")
 1209     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call/3")
 1210     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call/4")
 1211     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call/5")
 1212     (check-next-stream-line-equal _test-output-stream "    (foo)"               "F - test-convert-function-call/6")
 1213     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call/7")
 1214     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call/8")
 1215     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call/9")
 1216     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call/10")
 1217     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call/11")
 1218     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call/12")
 1219     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call/13")
 1220     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call/14")
 1221     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call/15")
 1222     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call/16")
 1223     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call/17")
 1224     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"  "F - test-convert-function-call/18")
 1225     (check-next-stream-line-equal _test-output-stream "    bb/copy-to-ebx 3/imm32"  "F - test-convert-function-call/19")
 1226     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call/20")
 1227     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-call/21")
 1228     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call/22")
 1229     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call/23")
 1230     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call/24")
 1231     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call/25")
 1232     # . epilogue
 1233     89/<- %esp 5/r32/ebp
 1234     5d/pop-to-ebp
 1235     c3/return
 1236 
 1237 test-convert-function-call-with-incorrect-inout-type:
 1238     # . prologue
 1239     55/push-ebp
 1240     89/<- %ebp 4/r32/esp
 1241     # setup
 1242     (clear-stream _test-input-stream)
 1243     (clear-stream $_test-input-buffered-file->buffer)
 1244     (clear-stream _test-output-stream)
 1245     (clear-stream $_test-output-buffered-file->buffer)
 1246     (clear-stream _test-error-stream)
 1247     (clear-stream $_test-error-buffered-file->buffer)
 1248     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1249     68/push 0/imm32
 1250     68/push 0/imm32
 1251     89/<- %edx 4/r32/esp
 1252     (tailor-exit-descriptor %edx 0x10)
 1253     #
 1254     (write _test-input-stream "fn f {\n")
 1255     (write _test-input-stream "  var x: int\n")
 1256     (write _test-input-stream "  g x\n")
 1257     (write _test-input-stream "}\n")
 1258     (write _test-input-stream "fn g a: foo {\n")
 1259     (write _test-input-stream "}\n")
 1260     # convert
 1261     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1262     # registers except esp clobbered at this point
 1263     # restore ed
 1264     89/<- %edx 4/r32/esp
 1265     (flush _test-output-buffered-file)
 1266     (flush _test-error-buffered-file)
 1267 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1273     # check output
 1274     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-inout-type: output should be empty")
 1275     (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")
 1276     # check that stop(1) was called
 1277     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-inout-type: exit status")
 1278     # don't restore from ebp
 1279     81 0/subop/add %esp 8/imm32
 1280     5d/pop-to-ebp
 1281     c3/return
 1282 
 1283 test-convert-function-call-with-too-few-inouts:
 1284     # . prologue
 1285     55/push-ebp
 1286     89/<- %ebp 4/r32/esp
 1287     # setup
 1288     (clear-stream _test-input-stream)
 1289     (clear-stream $_test-input-buffered-file->buffer)
 1290     (clear-stream _test-output-stream)
 1291     (clear-stream $_test-output-buffered-file->buffer)
 1292     (clear-stream _test-error-stream)
 1293     (clear-stream $_test-error-buffered-file->buffer)
 1294     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1295     68/push 0/imm32
 1296     68/push 0/imm32
 1297     89/<- %edx 4/r32/esp
 1298     (tailor-exit-descriptor %edx 0x10)
 1299     #
 1300     (write _test-input-stream "fn f {\n")
 1301     (write _test-input-stream "  g\n")
 1302     (write _test-input-stream "}\n")
 1303     (write _test-input-stream "fn g a: int {\n")
 1304     (write _test-input-stream "}\n")
 1305     # convert
 1306     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1307     # registers except esp clobbered at this point
 1308     # restore ed
 1309     89/<- %edx 4/r32/esp
 1310     (flush _test-output-buffered-file)
 1311     (flush _test-error-buffered-file)
 1312 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1318     # check output
 1319     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-few-inouts: output should be empty")
 1320     (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")
 1321     # check that stop(1) was called
 1322     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-few-inouts: exit status")
 1323     # don't restore from ebp
 1324     81 0/subop/add %esp 8/imm32
 1325     5d/pop-to-ebp
 1326     c3/return
 1327 
 1328 test-convert-function-call-with-too-many-inouts:
 1329     # . prologue
 1330     55/push-ebp
 1331     89/<- %ebp 4/r32/esp
 1332     # setup
 1333     (clear-stream _test-input-stream)
 1334     (clear-stream $_test-input-buffered-file->buffer)
 1335     (clear-stream _test-output-stream)
 1336     (clear-stream $_test-output-buffered-file->buffer)
 1337     (clear-stream _test-error-stream)
 1338     (clear-stream $_test-error-buffered-file->buffer)
 1339     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1340     68/push 0/imm32
 1341     68/push 0/imm32
 1342     89/<- %edx 4/r32/esp
 1343     (tailor-exit-descriptor %edx 0x10)
 1344     #
 1345     (write _test-input-stream "fn f {\n")
 1346     (write _test-input-stream "  var x: int\n")
 1347     (write _test-input-stream "  g x\n")
 1348     (write _test-input-stream "}\n")
 1349     (write _test-input-stream "fn g {\n")
 1350     (write _test-input-stream "}\n")
 1351     # convert
 1352     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1353     # registers except esp clobbered at this point
 1354     # restore ed
 1355     89/<- %edx 4/r32/esp
 1356     (flush _test-output-buffered-file)
 1357     (flush _test-error-buffered-file)
 1358 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1364     # check output
 1365     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-many-inouts: output should be empty")
 1366     (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")
 1367     # check that stop(1) was called
 1368     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-many-inouts: exit status")
 1369     # don't restore from ebp
 1370     81 0/subop/add %esp 8/imm32
 1371     5d/pop-to-ebp
 1372     c3/return
 1373 
 1374 test-convert-function-call-with-incorrect-output-type:
 1375     # . prologue
 1376     55/push-ebp
 1377     89/<- %ebp 4/r32/esp
 1378     # setup
 1379     (clear-stream _test-input-stream)
 1380     (clear-stream $_test-input-buffered-file->buffer)
 1381     (clear-stream _test-output-stream)
 1382     (clear-stream $_test-output-buffered-file->buffer)
 1383     (clear-stream _test-error-stream)
 1384     (clear-stream $_test-error-buffered-file->buffer)
 1385     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1386     68/push 0/imm32
 1387     68/push 0/imm32
 1388     89/<- %edx 4/r32/esp
 1389     (tailor-exit-descriptor %edx 0x10)
 1390     #
 1391     (write _test-input-stream "fn f {\n")
 1392     (write _test-input-stream "  var x/eax: int <- g\n")
 1393     (write _test-input-stream "}\n")
 1394     (write _test-input-stream "fn g -> a/eax: foo {\n")
 1395     (write _test-input-stream "}\n")
 1396     # convert
 1397     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1398     # registers except esp clobbered at this point
 1399     # restore ed
 1400     89/<- %edx 4/r32/esp
 1401     (flush _test-output-buffered-file)
 1402     (flush _test-error-buffered-file)
 1403 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1409     # check output
 1410     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-output-type: output should be empty")
 1411     (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")
 1412     # check that stop(1) was called
 1413     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-output-type: exit status")
 1414     # don't restore from ebp
 1415     81 0/subop/add %esp 8/imm32
 1416     5d/pop-to-ebp
 1417     c3/return
 1418 
 1419 test-convert-function-call-with-too-few-outputs:
 1420     # . prologue
 1421     55/push-ebp
 1422     89/<- %ebp 4/r32/esp
 1423     # setup
 1424     (clear-stream _test-input-stream)
 1425     (clear-stream $_test-input-buffered-file->buffer)
 1426     (clear-stream _test-output-stream)
 1427     (clear-stream $_test-output-buffered-file->buffer)
 1428     (clear-stream _test-error-stream)
 1429     (clear-stream $_test-error-buffered-file->buffer)
 1430     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1431     68/push 0/imm32
 1432     68/push 0/imm32
 1433     89/<- %edx 4/r32/esp
 1434     (tailor-exit-descriptor %edx 0x10)
 1435     #
 1436     (write _test-input-stream "fn f {\n")
 1437     (write _test-input-stream "  g\n")
 1438     (write _test-input-stream "}\n")
 1439     (write _test-input-stream "fn g -> a/eax: int {\n")
 1440     (write _test-input-stream "}\n")
 1441     # convert
 1442     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1443     # registers except esp clobbered at this point
 1444     # restore ed
 1445     89/<- %edx 4/r32/esp
 1446     (flush _test-output-buffered-file)
 1447     (flush _test-error-buffered-file)
 1448 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1454     # check output
 1455     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-few-outputs: output should be empty")
 1456     (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")
 1457     # check that stop(1) was called
 1458     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-few-outputs: exit status")
 1459     # don't restore from ebp
 1460     81 0/subop/add %esp 8/imm32
 1461     5d/pop-to-ebp
 1462     c3/return
 1463 
 1464 test-convert-function-call-with-too-many-outputs:
 1465     # . prologue
 1466     55/push-ebp
 1467     89/<- %ebp 4/r32/esp
 1468     # setup
 1469     (clear-stream _test-input-stream)
 1470     (clear-stream $_test-input-buffered-file->buffer)
 1471     (clear-stream _test-output-stream)
 1472     (clear-stream $_test-output-buffered-file->buffer)
 1473     (clear-stream _test-error-stream)
 1474     (clear-stream $_test-error-buffered-file->buffer)
 1475     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1476     68/push 0/imm32
 1477     68/push 0/imm32
 1478     89/<- %edx 4/r32/esp
 1479     (tailor-exit-descriptor %edx 0x10)
 1480     #
 1481     (write _test-input-stream "fn f {\n")
 1482     (write _test-input-stream "  var x/eax: int <- g\n")
 1483     (write _test-input-stream "}\n")
 1484     (write _test-input-stream "fn g {\n")
 1485     (write _test-input-stream "}\n")
 1486     # convert
 1487     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1488     # registers except esp clobbered at this point
 1489     # restore ed
 1490     89/<- %edx 4/r32/esp
 1491     (flush _test-output-buffered-file)
 1492     (flush _test-error-buffered-file)
 1493 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1499     # check output
 1500     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-many-outputs: output should be empty")
 1501     (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")
 1502     # check that stop(1) was called
 1503     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-many-outputs: exit status")
 1504     # don't restore from ebp
 1505     81 0/subop/add %esp 8/imm32
 1506     5d/pop-to-ebp
 1507     c3/return
 1508 
 1509 test-convert-function-call-with-incorrect-output-register:
 1510     # . prologue
 1511     55/push-ebp
 1512     89/<- %ebp 4/r32/esp
 1513     # setup
 1514     (clear-stream _test-input-stream)
 1515     (clear-stream $_test-input-buffered-file->buffer)
 1516     (clear-stream _test-output-stream)
 1517     (clear-stream $_test-output-buffered-file->buffer)
 1518     (clear-stream _test-error-stream)
 1519     (clear-stream $_test-error-buffered-file->buffer)
 1520     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1521     68/push 0/imm32
 1522     68/push 0/imm32
 1523     89/<- %edx 4/r32/esp
 1524     (tailor-exit-descriptor %edx 0x10)
 1525     #
 1526     (write _test-input-stream "fn f {\n")
 1527     (write _test-input-stream "  var x/ecx: int <- g\n")
 1528     (write _test-input-stream "}\n")
 1529     (write _test-input-stream "fn g -> a/eax: int {\n")
 1530     (write _test-input-stream "}\n")
 1531     # convert
 1532     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1533     # registers except esp clobbered at this point
 1534     # restore ed
 1535     89/<- %edx 4/r32/esp
 1536     (flush _test-output-buffered-file)
 1537     (flush _test-error-buffered-file)
 1538 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1544     # check output
 1545     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-output-register: output should be empty")
 1546     (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")
 1547     # check that stop(1) was called
 1548     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-output-register: exit status")
 1549     # don't restore from ebp
 1550     81 0/subop/add %esp 8/imm32
 1551     5d/pop-to-ebp
 1552     c3/return
 1553 
 1554 test-convert-function-with-local-var-dereferenced:
 1555     # . prologue
 1556     55/push-ebp
 1557     89/<- %ebp 4/r32/esp
 1558     # setup
 1559     (clear-stream _test-input-stream)
 1560     (clear-stream $_test-input-buffered-file->buffer)
 1561     (clear-stream _test-output-stream)
 1562     (clear-stream $_test-output-buffered-file->buffer)
 1563     #
 1564     (write _test-input-stream "fn foo {\n")
 1565     (write _test-input-stream "  var x/ecx: (addr int) <- copy 0\n")
 1566     (write _test-input-stream "  increment *x\n")
 1567     (write _test-input-stream "}\n")
 1568     # convert
 1569     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1570     (flush _test-output-buffered-file)
 1571 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1577     # check output
 1578     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-dereferenced/0")
 1579     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-dereferenced/1")
 1580     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-dereferenced/2")
 1581     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-dereferenced/3")
 1582     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-dereferenced/4")
 1583     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-dereferenced/5")
 1584     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-dereferenced/6")
 1585     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-local-var-dereferenced/7")
 1586     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *ecx"  "F - test-convert-function-with-local-var-dereferenced/8")
 1587     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-dereferenced/9")
 1588     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-dereferenced/10")
 1589     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-dereferenced/11")
 1590     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-dereferenced/12")
 1591     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-dereferenced/13")
 1592     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-dereferenced/14")
 1593     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-dereferenced/15")
 1594     # . epilogue
 1595     89/<- %esp 5/r32/ebp
 1596     5d/pop-to-ebp
 1597     c3/return
 1598 
 1599 # variables of type 'byte' are not allowed on the stack
 1600 test-convert-function-with-byte-operations:
 1601     # . prologue
 1602     55/push-ebp
 1603     89/<- %ebp 4/r32/esp
 1604     # setup
 1605     (clear-stream _test-input-stream)
 1606     (clear-stream $_test-input-buffered-file->buffer)
 1607     (clear-stream _test-output-stream)
 1608     (clear-stream $_test-output-buffered-file->buffer)
 1609     #
 1610     (write _test-input-stream "fn foo {\n")
 1611     (write _test-input-stream "  var x/eax: byte <- copy 0\n")
 1612     (write _test-input-stream "  var y/ecx: byte <- copy 0\n")
 1613     (write _test-input-stream "  y <- copy-byte x\n")
 1614     (write _test-input-stream "  var z/edx: (addr byte) <- copy 0\n")
 1615     (write _test-input-stream "  y <- copy-byte *z\n")
 1616     (write _test-input-stream "  copy-byte-to *z, x\n")
 1617     (write _test-input-stream "}\n")
 1618     # convert
 1619     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1620     (flush _test-output-buffered-file)
 1621 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1627     # check output
 1628     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-function-with-byte-operations/0")
 1629     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-function-with-byte-operations/1")
 1630     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-function-with-byte-operations/2")
 1631     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-function-with-byte-operations/3")
 1632     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-function-with-byte-operations/4")
 1633     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-function-with-byte-operations/5")
 1634     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-function-with-byte-operations/6")
 1635     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-function-with-byte-operations/7")
 1636     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-function-with-byte-operations/8")
 1637     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"                  "F - test-convert-function-with-byte-operations/9")
 1638     (check-next-stream-line-equal _test-output-stream "    8a/byte-> %eax 0x00000001/r32"           "F - test-convert-function-with-byte-operations/10")
 1639     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %edx"                    "F - test-convert-function-with-byte-operations/11")
 1640     (check-next-stream-line-equal _test-output-stream "    ba/copy-to-edx 0/imm32"                  "F - test-convert-function-with-byte-operations/12")
 1641     (check-next-stream-line-equal _test-output-stream "    8a/byte-> *edx 0x00000001/r32"           "F - test-convert-function-with-byte-operations/13")
 1642     (check-next-stream-line-equal _test-output-stream "    88/byte<- *edx 0x00000000/r32"           "F - test-convert-function-with-byte-operations/14")
 1643     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %edx"                     "F - test-convert-function-with-byte-operations/15")
 1644     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-function-with-byte-operations/16")
 1645     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-function-with-byte-operations/17")
 1646     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-function-with-byte-operations/18")
 1647     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-function-with-byte-operations/19")
 1648     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-function-with-byte-operations/20")
 1649     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-function-with-byte-operations/21")
 1650     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-function-with-byte-operations/22")
 1651     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-function-with-byte-operations/23")
 1652     # . epilogue
 1653     89/<- %esp 5/r32/ebp
 1654     5d/pop-to-ebp
 1655     c3/return
 1656 
 1657 # variables of type 'byte' _can_ be function args. They then occupy 4 bytes.
 1658 test-copy-byte-var-from-fn-arg:
 1659     # . prologue
 1660     55/push-ebp
 1661     89/<- %ebp 4/r32/esp
 1662     # setup
 1663     (clear-stream _test-input-stream)
 1664     (clear-stream $_test-input-buffered-file->buffer)
 1665     (clear-stream _test-output-stream)
 1666     (clear-stream $_test-output-buffered-file->buffer)
 1667     #
 1668     (write _test-input-stream "fn foo x: byte, y: int {\n")
 1669     (write _test-input-stream "  var a/eax: byte <- copy x\n")
 1670     (write _test-input-stream "  var b/eax: int <- copy y\n")
 1671     (write _test-input-stream "}\n")
 1672     # convert
 1673     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1674     (flush _test-output-buffered-file)
 1675 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1681     # check output
 1682     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-copy-byte-from-fn-arg/0")
 1683     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-copy-byte-from-fn-arg/1")
 1684     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-copy-byte-from-fn-arg/2")
 1685     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-copy-byte-from-fn-arg/3")
 1686     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-copy-byte-from-fn-arg/4")
 1687     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-copy-byte-from-fn-arg/5")
 1688     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-copy-byte-from-fn-arg/6")
 1689     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-copy-byte-from-fn-arg/7")
 1690     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x0000000c) 0x00000000/r32"  "F - test-copy-byte-from-fn-arg/8")
 1691     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"   "F - test-copy-byte-from-fn-arg/9")
 1692     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-copy-byte-from-fn-arg/10")
 1693     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-copy-byte-from-fn-arg/11")
 1694     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-copy-byte-from-fn-arg/12")
 1695     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-copy-byte-from-fn-arg/13")
 1696     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-copy-byte-from-fn-arg/14")
 1697     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-copy-byte-from-fn-arg/15")
 1698     # . epilogue
 1699     89/<- %esp 5/r32/ebp
 1700     5d/pop-to-ebp
 1701     c3/return
 1702 
 1703 test-convert-compare-register-with-literal:
 1704     # . prologue
 1705     55/push-ebp
 1706     89/<- %ebp 4/r32/esp
 1707     # setup
 1708     (clear-stream _test-input-stream)
 1709     (clear-stream $_test-input-buffered-file->buffer)
 1710     (clear-stream _test-output-stream)
 1711     (clear-stream $_test-output-buffered-file->buffer)
 1712     #
 1713     (write _test-input-stream "fn foo {\n")
 1714     (write _test-input-stream "  var x/ecx: int <- copy 0\n")
 1715     (write _test-input-stream "  compare x, 0\n")
 1716     (write _test-input-stream "}\n")
 1717     # convert
 1718     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1719     (flush _test-output-buffered-file)
 1720 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1726     # check output
 1727     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-compare-register-with-literal/0")
 1728     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-compare-register-with-literal/1")
 1729     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-compare-register-with-literal/2")
 1730     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-compare-register-with-literal/3")
 1731     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-compare-register-with-literal/4")
 1732     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-compare-register-with-literal/5")
 1733     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
 1734     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-compare-register-with-literal/7")
 1735     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %ecx 0/imm32"  "F - test-convert-compare-register-with-literal/8")
 1736     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
 1737     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-compare-register-with-literal/10")
 1738     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-compare-register-with-literal/11")
 1739     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-compare-register-with-literal/12")
 1740     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-compare-register-with-literal/13")
 1741     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-compare-register-with-literal/14")
 1742     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-compare-register-with-literal/15")
 1743     # . epilogue
 1744     89/<- %esp 5/r32/ebp
 1745     5d/pop-to-ebp
 1746     c3/return
 1747 
 1748 test-unknown-variable:
 1749     # . prologue
 1750     55/push-ebp
 1751     89/<- %ebp 4/r32/esp
 1752     # setup
 1753     (clear-stream _test-input-stream)
 1754     (clear-stream $_test-input-buffered-file->buffer)
 1755     (clear-stream _test-output-stream)
 1756     (clear-stream $_test-output-buffered-file->buffer)
 1757     (clear-stream _test-error-stream)
 1758     (clear-stream $_test-error-buffered-file->buffer)
 1759     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1760     68/push 0/imm32
 1761     68/push 0/imm32
 1762     89/<- %edx 4/r32/esp
 1763     (tailor-exit-descriptor %edx 0x10)
 1764     #
 1765     (write _test-input-stream "fn foo {\n")
 1766     (write _test-input-stream "  compare x, 0\n")
 1767     (write _test-input-stream "}\n")
 1768     # convert
 1769     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1770     # registers except esp clobbered at this point
 1771     # restore ed
 1772     89/<- %edx 4/r32/esp
 1773     (flush _test-output-buffered-file)
 1774     (flush _test-error-buffered-file)
 1775 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1781     # check output
 1782     (check-stream-equal _test-output-stream  ""  "F - test-unknown-variable: output should be empty")
 1783     (check-next-stream-line-equal _test-error-stream  "fn foo: unknown variable 'x'"  "F - test-unknown-variable: error message")
 1784     # check that stop(1) was called
 1785     (check-ints-equal *(edx+4) 2 "F - test-unknown-variable: exit status")
 1786     # don't restore from ebp
 1787     81 0/subop/add %esp 8/imm32
 1788     # . epilogue
 1789     5d/pop-to-ebp
 1790     c3/return
 1791 
 1792 test-convert-function-with-local-var-in-block:
 1793     # . prologue
 1794     55/push-ebp
 1795     89/<- %ebp 4/r32/esp
 1796     # setup
 1797     (clear-stream _test-input-stream)
 1798     (clear-stream $_test-input-buffered-file->buffer)
 1799     (clear-stream _test-output-stream)
 1800     (clear-stream $_test-output-buffered-file->buffer)
 1801     #
 1802     (write _test-input-stream "fn foo {\n")
 1803     (write _test-input-stream "  {\n")
 1804     (write _test-input-stream "    var x: int\n")
 1805     (write _test-input-stream "    increment x\n")
 1806     (write _test-input-stream "  }\n")
 1807     (write _test-input-stream "}\n")
 1808     # convert
 1809     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1810     (flush _test-output-buffered-file)
 1811 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1817     # check output
 1818     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-block/0")
 1819     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-block/1")
 1820     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-block/2")
 1821     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-block/3")
 1822     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-block/4")
 1823     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-block/5")
 1824     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-block/6")
 1825     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-local-var-in-block/7")
 1826     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-block/8")
 1827     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-block/9")
 1828     (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")
 1829     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-block/11")
 1830     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-local-var-in-block/12")
 1831     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-block/13")
 1832     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-block/14")
 1833     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-block/15")
 1834     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-block/16")
 1835     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-block/17")
 1836     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-block/18")
 1837     # . epilogue
 1838     89/<- %esp 5/r32/ebp
 1839     5d/pop-to-ebp
 1840     c3/return
 1841 
 1842 test-convert-function-with-local-var-in-named-block:
 1843     # . prologue
 1844     55/push-ebp
 1845     89/<- %ebp 4/r32/esp
 1846     # setup
 1847     (clear-stream _test-input-stream)
 1848     (clear-stream $_test-input-buffered-file->buffer)
 1849     (clear-stream _test-output-stream)
 1850     (clear-stream $_test-output-buffered-file->buffer)
 1851     #
 1852     (write _test-input-stream "fn foo {\n")
 1853     (write _test-input-stream "  $bar: {\n")
 1854     (write _test-input-stream "    var x: int\n")
 1855     (write _test-input-stream "    increment x\n")
 1856     (write _test-input-stream "  }\n")
 1857     (write _test-input-stream "}\n")
 1858     # convert
 1859     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1860     (flush _test-output-buffered-file)
 1861 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1867     # check output
 1868     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-named-block/0")
 1869     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-named-block/1")
 1870     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-named-block/2")
 1871     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-named-block/3")
 1872     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-named-block/4")
 1873     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-named-block/5")
 1874     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-named-block/6")
 1875     (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-local-var-in-named-block/7")
 1876     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-named-block/8")
 1877     (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")
 1878     (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")
 1879     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-named-block/11")
 1880     (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-local-var-in-named-block/12")
 1881     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-named-block/13")
 1882     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-named-block/14")
 1883     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-named-block/15")
 1884     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-named-block/16")
 1885     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-named-block/17")
 1886     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-named-block/18")
 1887     # . epilogue
 1888     89/<- %esp 5/r32/ebp
 1889     5d/pop-to-ebp
 1890     c3/return
 1891 
 1892 test-unknown-variable-in-named-block:
 1893     # . prologue
 1894     55/push-ebp
 1895     89/<- %ebp 4/r32/esp
 1896     # setup
 1897     (clear-stream _test-input-stream)
 1898     (clear-stream $_test-input-buffered-file->buffer)
 1899     (clear-stream _test-output-stream)
 1900     (clear-stream $_test-output-buffered-file->buffer)
 1901     (clear-stream _test-error-stream)
 1902     (clear-stream $_test-error-buffered-file->buffer)
 1903     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1904     68/push 0/imm32
 1905     68/push 0/imm32
 1906     89/<- %edx 4/r32/esp
 1907     (tailor-exit-descriptor %edx 0x10)
 1908     #
 1909     (write _test-input-stream "fn foo {\n")
 1910     (write _test-input-stream "  $a: {\n")
 1911     (write _test-input-stream "    compare x, 0\n")
 1912     (write _test-input-stream "  }\n")
 1913     (write _test-input-stream "}\n")
 1914     # convert
 1915     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1916     # registers except esp clobbered at this point
 1917     # restore ed
 1918     89/<- %edx 4/r32/esp
 1919     (flush _test-output-buffered-file)
 1920     (flush _test-error-buffered-file)
 1921 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1927     # check output
 1928     (check-stream-equal _test-output-stream  ""  "F - test-unknown-variable-in-named-block: output should be empty")
 1929     (check-next-stream-line-equal _test-error-stream  "fn foo: unknown variable 'x'"  "F - test-unknown-variable-in-named-block: error message")
 1930     # check that stop(1) was called
 1931     (check-ints-equal *(edx+4) 2 "F - test-unknown-variable-in-named-block: exit status")
 1932     # don't restore from ebp
 1933     81 0/subop/add %esp 8/imm32
 1934     # . epilogue
 1935     5d/pop-to-ebp
 1936     c3/return
 1937 
 1938 test-always-shadow-outermost-reg-vars-in-function:
 1939     # . prologue
 1940     55/push-ebp
 1941     89/<- %ebp 4/r32/esp
 1942     # setup
 1943     (clear-stream _test-input-stream)
 1944     (clear-stream $_test-input-buffered-file->buffer)
 1945     (clear-stream _test-output-stream)
 1946     (clear-stream $_test-output-buffered-file->buffer)
 1947     #
 1948     (write _test-input-stream "fn foo {\n")
 1949     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1950     (write _test-input-stream "}\n")
 1951     # convert
 1952     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1953     (flush _test-output-buffered-file)
 1954 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1960     # check output
 1961     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-always-shadow-outermost-reg-vars-in-function/0")
 1962     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-always-shadow-outermost-reg-vars-in-function/1")
 1963     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-always-shadow-outermost-reg-vars-in-function/2")
 1964     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-always-shadow-outermost-reg-vars-in-function/3")
 1965     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-always-shadow-outermost-reg-vars-in-function/4")
 1966     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-always-shadow-outermost-reg-vars-in-function/5")
 1967     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
 1968     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-always-shadow-outermost-reg-vars-in-function/8")
 1969     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
 1970     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-always-shadow-outermost-reg-vars-in-function/12")
 1971     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-always-shadow-outermost-reg-vars-in-function/13")
 1972     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-always-shadow-outermost-reg-vars-in-function/14")
 1973     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-always-shadow-outermost-reg-vars-in-function/15")
 1974     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-always-shadow-outermost-reg-vars-in-function/16")
 1975     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-always-shadow-outermost-reg-vars-in-function/17")
 1976     # . epilogue
 1977     89/<- %esp 5/r32/ebp
 1978     5d/pop-to-ebp
 1979     c3/return
 1980 
 1981 _pending-test-clobber-dead-local:
 1982     # . prologue
 1983     55/push-ebp
 1984     89/<- %ebp 4/r32/esp
 1985     # setup
 1986     (clear-stream _test-input-stream)
 1987     (clear-stream $_test-input-buffered-file->buffer)
 1988     (clear-stream _test-output-stream)
 1989     (clear-stream $_test-output-buffered-file->buffer)
 1990     #
 1991     (write _test-input-stream "fn foo {\n")
 1992     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1993     (write _test-input-stream "  {\n")
 1994     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 1995     (write _test-input-stream "  }\n")
 1996     (write _test-input-stream "}\n")
 1997     # convert
 1998     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1999     (flush _test-output-buffered-file)
 2000 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2006     # check output
 2007     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-clobber-dead-local/0")
 2008     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-clobber-dead-local/1")
 2009     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-clobber-dead-local/2")
 2010     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-clobber-dead-local/3")
 2011     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-clobber-dead-local/4")
 2012     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-clobber-dead-local/5")
 2013     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-clobber-dead-local/6")
 2014     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-clobber-dead-local/7")
 2015     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-clobber-dead-local/8")
 2016     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-clobber-dead-local/9")
 2017     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-clobber-dead-local/10")  # no push/pop here
 2018     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-clobber-dead-local/11")
 2019     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-clobber-dead-local/12")
 2020     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-clobber-dead-local/13")
 2021     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-clobber-dead-local/14")
 2022     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-clobber-dead-local/15")
 2023     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-clobber-dead-local/16")
 2024     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-clobber-dead-local/17")
 2025     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-clobber-dead-local/18")
 2026     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-clobber-dead-local/19")
 2027     # . epilogue
 2028     89/<- %esp 5/r32/ebp
 2029     5d/pop-to-ebp
 2030     c3/return
 2031 
 2032 test-shadow-live-local:
 2033     # . prologue
 2034     55/push-ebp
 2035     89/<- %ebp 4/r32/esp
 2036     # setup
 2037     (clear-stream _test-input-stream)
 2038     (clear-stream $_test-input-buffered-file->buffer)
 2039     (clear-stream _test-output-stream)
 2040     (clear-stream $_test-output-buffered-file->buffer)
 2041     #
 2042     (write _test-input-stream "fn foo {\n")
 2043     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2044     (write _test-input-stream "  {\n")
 2045     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 2046     (write _test-input-stream "  }\n")
 2047     (write _test-input-stream "  x <- increment\n")
 2048     (write _test-input-stream "}\n")
 2049     # convert
 2050     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2051     (flush _test-output-buffered-file)
 2052 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2058     # check output
 2059     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-live-local/0")
 2060     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-live-local/1")
 2061     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-live-local/2")
 2062     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-live-local/3")
 2063     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-live-local/4")
 2064     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-live-local/5")
 2065     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-live-local/6")
 2066     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-live-local/7")
 2067     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-live-local/8")
 2068     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-live-local/9")
 2069     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-live-local/10")
 2070     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-live-local/11")
 2071     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-live-local/12")
 2072     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-live-local/13")
 2073     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-live-local/14")
 2074     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-live-local/15")
 2075     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-live-local/16")
 2076     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-live-local/17")
 2077     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-live-local/18")
 2078     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-live-local/19")
 2079     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-live-local/20")
 2080     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-live-local/21")
 2081     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-live-local/22")
 2082     # . epilogue
 2083     89/<- %esp 5/r32/ebp
 2084     5d/pop-to-ebp
 2085     c3/return
 2086 
 2087 test-shadow-name:
 2088     # . prologue
 2089     55/push-ebp
 2090     89/<- %ebp 4/r32/esp
 2091     # setup
 2092     (clear-stream _test-input-stream)
 2093     (clear-stream $_test-input-buffered-file->buffer)
 2094     (clear-stream _test-output-stream)
 2095     (clear-stream $_test-output-buffered-file->buffer)
 2096     #
 2097     (write _test-input-stream "fn foo {\n")
 2098     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2099     (write _test-input-stream "  {\n")
 2100     (write _test-input-stream "    var x/edx: int <- copy 4\n")
 2101     (write _test-input-stream "  }\n")
 2102     (write _test-input-stream "  x <- increment\n")
 2103     (write _test-input-stream "}\n")
 2104     # convert
 2105     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2106     (flush _test-output-buffered-file)
 2107 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2113     # check output
 2114     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-name/0")
 2115     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-name/1")
 2116     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-name/2")
 2117     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-name/3")
 2118     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-name/4")
 2119     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-name/5")
 2120     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-name/6")
 2121     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-name/7")
 2122     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-name/8")
 2123     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-name/9")
 2124     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %edx"  "F - test-shadow-name/10")
 2125     (check-next-stream-line-equal _test-output-stream "      ba/copy-to-edx 4/imm32"  "F - test-shadow-name/11")
 2126     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %edx" "F - test-shadow-name/12")
 2127     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-name/13")
 2128     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-name/14")
 2129     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-name/15")
 2130     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-name/16")
 2131     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-name/17")
 2132     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-name/18")
 2133     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-name/19")
 2134     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-name/20")
 2135     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-name/21")
 2136     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-name/22")
 2137     # . epilogue
 2138     89/<- %esp 5/r32/ebp
 2139     5d/pop-to-ebp
 2140     c3/return
 2141 
 2142 test-shadow-name-2:
 2143     # . prologue
 2144     55/push-ebp
 2145     89/<- %ebp 4/r32/esp
 2146     # setup
 2147     (clear-stream _test-input-stream)
 2148     (clear-stream $_test-input-buffered-file->buffer)
 2149     (clear-stream _test-output-stream)
 2150     (clear-stream $_test-output-buffered-file->buffer)
 2151     #
 2152     (write _test-input-stream "fn foo {\n")
 2153     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2154     (write _test-input-stream "  {\n")
 2155     (write _test-input-stream "    var x/edx: int <- copy 4\n")
 2156     (write _test-input-stream "    var y/ecx: int <- copy 5\n")
 2157     (write _test-input-stream "  }\n")
 2158     (write _test-input-stream "  x <- increment\n")
 2159     (write _test-input-stream "}\n")
 2160     # convert
 2161     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2162     (flush _test-output-buffered-file)
 2163 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2169     # check output
 2170     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-name-2/0")
 2171     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-name-2/1")
 2172     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-name-2/2")
 2173     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-name-2/3")
 2174     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-name-2/4")
 2175     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-name-2/5")
 2176     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-name-2/6")
 2177     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-name-2/7")
 2178     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-name-2/8")
 2179     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-name-2/9")
 2180     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %edx"  "F - test-shadow-name-2/10")
 2181     (check-next-stream-line-equal _test-output-stream "      ba/copy-to-edx 4/imm32"  "F - test-shadow-name-2/11")
 2182     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-name-2/12")
 2183     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 5/imm32"  "F - test-shadow-name-2/13")
 2184     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-name-2/14")
 2185     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %edx" "F - test-shadow-name-2/15")
 2186     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-name-2/16")
 2187     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-name-2/17")
 2188     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-name-2/18")
 2189     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-name-2/19")
 2190     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-name-2/20")
 2191     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-name-2/21")
 2192     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-name-2/22")
 2193     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-name-2/23")
 2194     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-name-2/24")
 2195     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-name-2/25")
 2196     # . epilogue
 2197     89/<- %esp 5/r32/ebp
 2198     5d/pop-to-ebp
 2199     c3/return
 2200 
 2201 test-do-not-spill-same-register-in-block:
 2202     # . prologue
 2203     55/push-ebp
 2204     89/<- %ebp 4/r32/esp
 2205     # setup
 2206     (clear-stream _test-input-stream)
 2207     (clear-stream $_test-input-buffered-file->buffer)
 2208     (clear-stream _test-output-stream)
 2209     (clear-stream $_test-output-buffered-file->buffer)
 2210     #
 2211     (write _test-input-stream "fn foo {\n")
 2212     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2213     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2214     (write _test-input-stream "  y <- increment\n")
 2215     (write _test-input-stream "}\n")
 2216     # convert
 2217     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2218     (flush _test-output-buffered-file)
 2219 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2225     # check output
 2226     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-do-not-spill-same-register-in-block/0")
 2227     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-do-not-spill-same-register-in-block/1")
 2228     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-do-not-spill-same-register-in-block/2")
 2229     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-do-not-spill-same-register-in-block/3")
 2230     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-do-not-spill-same-register-in-block/4")
 2231     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-do-not-spill-same-register-in-block/5")
 2232     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-do-not-spill-same-register-in-block/6")
 2233     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-do-not-spill-same-register-in-block/7")
 2234     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-do-not-spill-same-register-in-block/8")
 2235     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-do-not-spill-same-register-in-block/9")
 2236     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-do-not-spill-same-register-in-block/10")
 2237     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-do-not-spill-same-register-in-block/11")
 2238     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-do-not-spill-same-register-in-block/12")
 2239     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-do-not-spill-same-register-in-block/13")
 2240     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-do-not-spill-same-register-in-block/14")
 2241     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-do-not-spill-same-register-in-block/15")
 2242     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-do-not-spill-same-register-in-block/16")
 2243     # . epilogue
 2244     89/<- %esp 5/r32/ebp
 2245     5d/pop-to-ebp
 2246     c3/return
 2247 
 2248 test-spill-different-register-in-block:
 2249     # . prologue
 2250     55/push-ebp
 2251     89/<- %ebp 4/r32/esp
 2252     # setup
 2253     (clear-stream _test-input-stream)
 2254     (clear-stream $_test-input-buffered-file->buffer)
 2255     (clear-stream _test-output-stream)
 2256     (clear-stream $_test-output-buffered-file->buffer)
 2257     #
 2258     (write _test-input-stream "fn foo {\n")
 2259     (write _test-input-stream "  var x/eax: int <- copy 3\n")
 2260     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2261     (write _test-input-stream "  y <- increment\n")
 2262     (write _test-input-stream "}\n")
 2263     # convert
 2264     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2265     (flush _test-output-buffered-file)
 2266 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2272     # check output
 2273     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-spill-different-register-in-block/0")
 2274     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-spill-different-register-in-block/1")
 2275     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-spill-different-register-in-block/2")
 2276     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-spill-different-register-in-block/3")
 2277     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-spill-different-register-in-block/4")
 2278     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-spill-different-register-in-block/5")
 2279     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-spill-different-register-in-block/6")
 2280     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-spill-different-register-in-block/7")
 2281     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-spill-different-register-in-block/8")
 2282     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-spill-different-register-in-block/9")
 2283     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-spill-different-register-in-block/10")
 2284     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-spill-different-register-in-block/11")
 2285     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-spill-different-register-in-block/12")
 2286     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-spill-different-register-in-block/13")
 2287     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-spill-different-register-in-block/14")
 2288     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-spill-different-register-in-block/15")
 2289     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-spill-different-register-in-block/16")
 2290     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-spill-different-register-in-block/17")
 2291     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-spill-different-register-in-block/18")
 2292     # . epilogue
 2293     89/<- %esp 5/r32/ebp
 2294     5d/pop-to-ebp
 2295     c3/return
 2296 
 2297 test-shadow-live-output:
 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 -> x/ecx: int {\n")
 2308     (write _test-input-stream "  x <- copy 3\n")
 2309     (write _test-input-stream "  {\n")
 2310     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 2311     (write _test-input-stream "  }\n")
 2312     (write _test-input-stream "  x <- increment\n")
 2313     (write _test-input-stream "}\n")
 2314     # convert
 2315     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2316     (flush _test-output-buffered-file)
 2317 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2323     # check output
 2324     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-live-output/0")
 2325     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-live-output/1")
 2326     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-live-output/2")
 2327     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-live-output/3")
 2328     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-live-output/4")
 2329     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-live-output/5")
 2330     (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
 2331     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-live-output/8")
 2332     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-live-output/9")
 2333     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-live-output/10")
 2334     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-live-output/11")
 2335     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-live-output/12")
 2336     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-live-output/13")
 2337     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-live-output/14")
 2338     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-live-output/15")
 2339     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-live-output/17")
 2340     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-live-output/18")
 2341     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-live-output/19")
 2342     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-live-output/20")
 2343     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-live-output/21")
 2344     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-live-output/21")
 2345     # . epilogue
 2346     89/<- %esp 5/r32/ebp
 2347     5d/pop-to-ebp
 2348     c3/return
 2349 
 2350 test-stmt-defines-output-in-same-register-as-inout:
 2351     # . prologue
 2352     55/push-ebp
 2353     89/<- %ebp 4/r32/esp
 2354     # setup
 2355     (clear-stream _test-input-stream)
 2356     (clear-stream $_test-input-buffered-file->buffer)
 2357     (clear-stream _test-output-stream)
 2358     (clear-stream $_test-output-buffered-file->buffer)
 2359     (clear-stream _test-error-stream)
 2360     (clear-stream $_test-error-buffered-file->buffer)
 2361     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 2362     68/push 0/imm32
 2363     68/push 0/imm32
 2364     89/<- %edx 4/r32/esp
 2365     (tailor-exit-descriptor %edx 0x10)
 2366     #
 2367     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2368     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2369     (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
 2370     (write _test-input-stream "}\n")
 2371     # convert
 2372     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 2373     # registers except esp clobbered at this point
 2374     # restore ed
 2375     89/<- %edx 4/r32/esp
 2376     (flush _test-output-buffered-file)
 2377     (flush _test-error-buffered-file)
 2378 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2384     # no error; we looked up 'y' correctly before pushing the binding for 'x'
 2385     (check-stream-equal _test-error-stream  ""  "F - test-stmt-defines-output-in-same-register-as-inout: error stream should be empty")
 2386     # don't bother checking the generated code; that's in the test 'test-local-clobbered-by-fn-output' below
 2387     # don't restore from ebp
 2388     81 0/subop/add %esp 8/imm32
 2389     # . epilogue
 2390     5d/pop-to-ebp
 2391     c3/return
 2392 
 2393 test-local-clobbered-by-fn-output:
 2394     # . prologue
 2395     55/push-ebp
 2396     89/<- %ebp 4/r32/esp
 2397     # setup
 2398     (clear-stream _test-input-stream)
 2399     (clear-stream $_test-input-buffered-file->buffer)
 2400     (clear-stream _test-output-stream)
 2401     (clear-stream $_test-output-buffered-file->buffer)
 2402     #
 2403     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2404     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2405     (write _test-input-stream "  x <- copy y\n")
 2406     (write _test-input-stream "}\n")
 2407     # convert
 2408     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2409     (flush _test-output-buffered-file)
 2410 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2416     # check output
 2417     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-local-clobbered-by-fn-output/0")
 2418     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-local-clobbered-by-fn-output/1")
 2419     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-local-clobbered-by-fn-output/2")
 2420     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-local-clobbered-by-fn-output/3")
 2421     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-local-clobbered-by-fn-output/4")
 2422     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-local-clobbered-by-fn-output/5")
 2423     (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
 2424     (check-next-stream-line-equal _test-output-stream "    89/<- %ecx 0x00000001/r32"  "F - test-local-clobbered-by-fn-output/7")
 2425     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-local-clobbered-by-fn-output/8")
 2426     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-local-clobbered-by-fn-output/9")
 2427     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-local-clobbered-by-fn-output/10")
 2428     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-local-clobbered-by-fn-output/11")
 2429     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-local-clobbered-by-fn-output/12")
 2430     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-local-clobbered-by-fn-output/13")
 2431     # . epilogue
 2432     89/<- %esp 5/r32/ebp
 2433     5d/pop-to-ebp
 2434     c3/return
 2435 
 2436 test-read-output:
 2437     # . prologue
 2438     55/push-ebp
 2439     89/<- %ebp 4/r32/esp
 2440     # setup
 2441     (clear-stream _test-input-stream)
 2442     (clear-stream $_test-input-buffered-file->buffer)
 2443     (clear-stream _test-output-stream)
 2444     (clear-stream $_test-output-buffered-file->buffer)
 2445     #
 2446     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2447     (write _test-input-stream "  x <- copy 0x34\n")
 2448     (write _test-input-stream "  compare x, 0x35\n")
 2449     (write _test-input-stream "}\n")
 2450     # convert
 2451     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2452     (flush _test-output-buffered-file)
 2453 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2459     # check output
 2460     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-read-output/0")
 2461     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-read-output/1")
 2462     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-read-output/2")
 2463     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-read-output/3")
 2464     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-read-output/4")
 2465     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-read-output/5")
 2466     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0x34/imm32"  "F - test-read-output/6")
 2467     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %ecx 0x35/imm32"  "F - test-read-output/7")
 2468     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-read-output/8")
 2469     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-read-output/9")
 2470     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-read-output/10")
 2471     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-read-output/11")
 2472     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-read-output/12")
 2473     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-read-output/13")
 2474     # . epilogue
 2475     89/<- %esp 5/r32/ebp
 2476     5d/pop-to-ebp
 2477     c3/return
 2478 
 2479 test-fn-output-written-in-inner-block:
 2480     # . prologue
 2481     55/push-ebp
 2482     89/<- %ebp 4/r32/esp
 2483     # setup
 2484     (clear-stream _test-input-stream)
 2485     (clear-stream $_test-input-buffered-file->buffer)
 2486     (clear-stream _test-output-stream)
 2487     (clear-stream $_test-output-buffered-file->buffer)
 2488     #
 2489     (write _test-input-stream "fn foo -> out/edi: int {\n")
 2490     (write _test-input-stream "  var a/eax: int <- copy 3\n")  # define outer local
 2491     (write _test-input-stream "  {\n")
 2492     (write _test-input-stream "    var a/ecx: int <- copy 4\n")  # shadow outer local
 2493     (write _test-input-stream "    out <- copy a\n")  # write to fn output
 2494     (write _test-input-stream "  }\n")
 2495     (write _test-input-stream "  compare a, 0\n")  # use outer local
 2496     (write _test-input-stream "}\n")
 2497     # convert
 2498     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2499     (flush _test-output-buffered-file)
 2500 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2506     # no error; defining 'out' didn't interfere with the reclamation of 'b'
 2507     # check output
 2508     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-fn-output-written-in-inner-block/0")
 2509     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-fn-output-written-in-inner-block/1")
 2510     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-fn-output-written-in-inner-block/2")
 2511     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-fn-output-written-in-inner-block/3")
 2512     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-fn-output-written-in-inner-block/4")
 2513     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-fn-output-written-in-inner-block/5")
 2514     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-fn-output-written-in-inner-block/6")
 2515     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-fn-output-written-in-inner-block/7")
 2516     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-fn-output-written-in-inner-block/8")
 2517     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-fn-output-written-in-inner-block/9")
 2518     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-fn-output-written-in-inner-block/10")
 2519     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-fn-output-written-in-inner-block/10")
 2520     (check-next-stream-line-equal _test-output-stream "      89/<- %edi 0x00000001/r32"  "F - test-fn-output-written-in-inner-block/11")
 2521     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx"  "F - test-fn-output-written-in-inner-block/12")
 2522     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-fn-output-written-in-inner-block/13")
 2523     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-fn-output-written-in-inner-block/14")
 2524     (check-next-stream-line-equal _test-output-stream "    3d/compare-eax-with 0/imm32"  "F - test-fn-output-written-in-inner-block/15")
 2525     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-fn-output-written-in-inner-block/16")
 2526     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-fn-output-written-in-inner-block/17")
 2527     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-fn-output-written-in-inner-block/18")
 2528     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-fn-output-written-in-inner-block/19")
 2529     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-fn-output-written-in-inner-block/20")
 2530     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-fn-output-written-in-inner-block/21")
 2531     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-fn-output-written-in-inner-block/22")
 2532     # . epilogue
 2533     89/<- %esp 5/r32/ebp
 2534     5d/pop-to-ebp
 2535     c3/return
 2536 
 2537 test-convert-function-with-branches-in-block:
 2538     # . prologue
 2539     55/push-ebp
 2540     89/<- %ebp 4/r32/esp
 2541     # setup
 2542     (clear-stream _test-input-stream)
 2543     (clear-stream $_test-input-buffered-file->buffer)
 2544     (clear-stream _test-output-stream)
 2545     (clear-stream $_test-output-buffered-file->buffer)
 2546     #
 2547     (write _test-input-stream "fn foo x: int {\n")
 2548     (write _test-input-stream "  {\n")
 2549     (write _test-input-stream "    break-if->=\n")
 2550     (write _test-input-stream "    loop-if-addr<\n")
 2551     (write _test-input-stream "    increment x\n")
 2552     (write _test-input-stream "    loop\n")
 2553     (write _test-input-stream "  }\n")
 2554     (write _test-input-stream "}\n")
 2555     # convert
 2556     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2557     (flush _test-output-buffered-file)
 2558 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2564     # check output
 2565     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-block/0")
 2566     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-block/1")
 2567     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-block/2")
 2568     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-block/3")
 2569     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-block/4")
 2570     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-block/5")
 2571     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-block/6")
 2572     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-in-block/7")
 2573     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/8")
 2574     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-block/9")
 2575     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-in-block/10")
 2576     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/11")
 2577     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/12")
 2578     (check-next-stream-line-equal _test-output-stream "        0f 83/jump-if-addr>= break/disp32"  "F - test-convert-function-with-branches-in-block/13")
 2579     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:loop/disp32"  "F - test-convert-function-with-branches-in-block/14")
 2580     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/15")
 2581     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-block/16")
 2582     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-in-block/17")
 2583     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-block/18")
 2584     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-in-block/19")
 2585     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-block/20")
 2586     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-block/21")
 2587     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-block/22")
 2588     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-block/23")
 2589     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-block/24")
 2590     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-block/25")
 2591     # . epilogue
 2592     89/<- %esp 5/r32/ebp
 2593     5d/pop-to-ebp
 2594     c3/return
 2595 
 2596 test-convert-function-with-branches-in-named-block:
 2597     # . prologue
 2598     55/push-ebp
 2599     89/<- %ebp 4/r32/esp
 2600     # setup
 2601     (clear-stream _test-input-stream)
 2602     (clear-stream $_test-input-buffered-file->buffer)
 2603     (clear-stream _test-output-stream)
 2604     (clear-stream $_test-output-buffered-file->buffer)
 2605     #
 2606     (write _test-input-stream "fn foo x: int {\n")
 2607     (write _test-input-stream "  $bar: {\n")
 2608     (write _test-input-stream "    break-if->= $bar\n")
 2609     (write _test-input-stream "    loop-if-addr< $bar\n")
 2610     (write _test-input-stream "    increment x\n")
 2611     (write _test-input-stream "    loop\n")
 2612     (write _test-input-stream "  }\n")
 2613     (write _test-input-stream "}\n")
 2614     # convert
 2615     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2616     (flush _test-output-buffered-file)
 2617 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2623     # check output
 2624     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-named-block/0")
 2625     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-named-block/1")
 2626     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-named-block/2")
 2627     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-named-block/3")
 2628     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-named-block/4")
 2629     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-named-block/5")
 2630     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-named-block/6")
 2631     (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-branches-in-named-block/7")
 2632     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-named-block/8")
 2633     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-named-block/9")
 2634     (check-next-stream-line-equal _test-output-stream "        e9/jump $bar:break/disp32"  "F - test-convert-function-with-branches-in-named-block/10")
 2635     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-named-block/11")
 2636     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-named-block/12")
 2637     (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")
 2638     (check-next-stream-line-equal _test-output-stream "        e9/jump $bar:loop/disp32"  "F - test-convert-function-with-branches-in-named-block/14")
 2639     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-named-block/15")
 2640     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-named-block/16")
 2641     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"   "F - test-convert-function-with-branches-in-named-block/17")
 2642     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-named-block/18")
 2643     (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-branches-in-named-block/19")
 2644     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-named-block/20")
 2645     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-named-block/21")
 2646     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-named-block/22")
 2647     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-named-block/23")
 2648     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-named-block/24")
 2649     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-named-block/25")
 2650     # . epilogue
 2651     89/<- %esp 5/r32/ebp
 2652     5d/pop-to-ebp
 2653     c3/return
 2654 
 2655 test-convert-function-with-var-in-nested-block:
 2656     # . prologue
 2657     55/push-ebp
 2658     89/<- %ebp 4/r32/esp
 2659     # setup
 2660     (clear-stream _test-input-stream)
 2661     (clear-stream $_test-input-buffered-file->buffer)
 2662     (clear-stream _test-output-stream)
 2663     (clear-stream $_test-output-buffered-file->buffer)
 2664     #
 2665     (write _test-input-stream "fn foo x: int {\n")
 2666     (write _test-input-stream "  {\n")
 2667     (write _test-input-stream "    {\n")
 2668     (write _test-input-stream "      var x: int\n")
 2669     (write _test-input-stream "      increment x\n")
 2670     (write _test-input-stream "    }\n")
 2671     (write _test-input-stream "  }\n")
 2672     (write _test-input-stream "}\n")
 2673     # convert
 2674     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2675     (flush _test-output-buffered-file)
 2676 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2682     # check output
 2683     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-var-in-nested-block/0")
 2684     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-var-in-nested-block/1")
 2685     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-var-in-nested-block/2")
 2686     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-var-in-nested-block/3")
 2687     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-var-in-nested-block/4")
 2688     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-var-in-nested-block/5")
 2689     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-var-in-nested-block/6")
 2690     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-var-in-nested-block/7")
 2691     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-var-in-nested-block/8")
 2692     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-var-in-nested-block/9")
 2693     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-var-in-nested-block/10")
 2694     (check-next-stream-line-equal _test-output-stream "        ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-var-in-nested-block/11")
 2695     (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")
 2696     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-var-in-nested-block/13")
 2697     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-var-in-nested-block/14")
 2698     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-var-in-nested-block/15")
 2699     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-var-in-nested-block/16")
 2700     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-var-in-nested-block/17")
 2701     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-var-in-nested-block/18")
 2702     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-var-in-nested-block/19")
 2703     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-var-in-nested-block/20")
 2704     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-var-in-nested-block/21")
 2705     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-var-in-nested-block/22")
 2706     # . epilogue
 2707     89/<- %esp 5/r32/ebp
 2708     5d/pop-to-ebp
 2709     c3/return
 2710 
 2711 test-convert-function-with-multiple-vars-in-nested-blocks:
 2712     # . prologue
 2713     55/push-ebp
 2714     89/<- %ebp 4/r32/esp
 2715     # setup
 2716     (clear-stream _test-input-stream)
 2717     (clear-stream $_test-input-buffered-file->buffer)
 2718     (clear-stream _test-output-stream)
 2719     (clear-stream $_test-output-buffered-file->buffer)
 2720     #
 2721     (write _test-input-stream "fn foo x: int {\n")
 2722     (write _test-input-stream "  {\n")
 2723     (write _test-input-stream "    var x/eax: int <- copy 0\n")
 2724     (write _test-input-stream "    {\n")
 2725     (write _test-input-stream "      var y: int\n")
 2726     (write _test-input-stream "      x <- add y\n")
 2727     (write _test-input-stream "    }\n")
 2728     (write _test-input-stream "  }\n")
 2729     (write _test-input-stream "}\n")
 2730     # convert
 2731     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2732     (flush _test-output-buffered-file)
 2733 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2739     # check output
 2740     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-multiple-vars-in-nested-blocks/0")
 2741     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/1")
 2742     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-multiple-vars-in-nested-blocks/2")
 2743     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/3")
 2744     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/4")
 2745     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/5")
 2746     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/6")
 2747     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/7")
 2748     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %eax"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/8")
 2749     (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")
 2750     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/10")
 2751     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/11")
 2752     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-multiple-vars-in-nested-blocks/12")
 2753     (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")
 2754     (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")
 2755     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/15")
 2756     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/16")
 2757     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %eax"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/17")
 2758     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/18")
 2759     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/19")
 2760     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/20")
 2761     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/21")
 2762     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/22")
 2763     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/23")
 2764     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-multiple-vars-in-nested-blocks/24")
 2765     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-multiple-vars-in-nested-blocks/25")
 2766     # . epilogue
 2767     89/<- %esp 5/r32/ebp
 2768     5d/pop-to-ebp
 2769     c3/return
 2770 
 2771 test-convert-function-with-branches-and-local-vars:
 2772     # A conditional 'break' after a 'var' in a block is converted into a
 2773     # nested block that performs all necessary cleanup before jumping. This
 2774     # results in some ugly code duplication.
 2775     # . prologue
 2776     55/push-ebp
 2777     89/<- %ebp 4/r32/esp
 2778     # setup
 2779     (clear-stream _test-input-stream)
 2780     (clear-stream $_test-input-buffered-file->buffer)
 2781     (clear-stream _test-output-stream)
 2782     (clear-stream $_test-output-buffered-file->buffer)
 2783     #
 2784     (write _test-input-stream "fn foo {\n")
 2785     (write _test-input-stream "  {\n")
 2786     (write _test-input-stream "    var x: int\n")
 2787     (write _test-input-stream "    break-if->=\n")
 2788     (write _test-input-stream "    increment x\n")
 2789     (write _test-input-stream "  }\n")
 2790     (write _test-input-stream "}\n")
 2791     # convert
 2792     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2793     (flush _test-output-buffered-file)
 2794 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2800     # check output
 2801     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-local-vars/0")
 2802     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-local-vars/1")
 2803     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-local-vars/2")
 2804     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-and-local-vars/3")
 2805     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-local-vars/4")
 2806     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-local-vars/5")
 2807     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-local-vars/6")
 2808     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-local-vars/7")
 2809     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-local-vars/8")
 2810     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-local-vars/9")
 2811     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-and-local-vars/10")
 2812     (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")
 2813     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-and-local-vars/12")
 2814     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-local-vars/13")
 2815     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-branches-and-local-vars/14")
 2816     (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")
 2817     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-local-vars/16")
 2818     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-local-vars/17")
 2819     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-local-vars/18")
 2820     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-local-vars/19")
 2821     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-local-vars/20")
 2822     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-and-local-vars/21")
 2823     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-local-vars/22")
 2824     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-local-vars/23")
 2825     # . epilogue
 2826     89/<- %esp 5/r32/ebp
 2827     5d/pop-to-ebp
 2828     c3/return
 2829 
 2830 test-convert-function-with-conditional-loops-and-local-vars:
 2831     # A conditional 'loop' after a 'var' in a block is converted into a nested
 2832     # block that performs all necessary cleanup before jumping. This results
 2833     # in some ugly code duplication.
 2834     # . prologue
 2835     55/push-ebp
 2836     89/<- %ebp 4/r32/esp
 2837     # setup
 2838     (clear-stream _test-input-stream)
 2839     (clear-stream $_test-input-buffered-file->buffer)
 2840     (clear-stream _test-output-stream)
 2841     (clear-stream $_test-output-buffered-file->buffer)
 2842     #
 2843     (write _test-input-stream "fn foo {\n")
 2844     (write _test-input-stream "  {\n")
 2845     (write _test-input-stream "    var x: int\n")
 2846     (write _test-input-stream "    loop-if->=\n")
 2847     (write _test-input-stream "    increment x\n")
 2848     (write _test-input-stream "  }\n")
 2849     (write _test-input-stream "}\n")
 2850     # convert
 2851     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2852     (flush _test-output-buffered-file)
 2853 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2859     # check output
 2860     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-conditional-loops-and-local-vars/0")
 2861     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-conditional-loops-and-local-vars/1")
 2862     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-conditional-loops-and-local-vars/2")
 2863     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-conditional-loops-and-local-vars/3")
 2864     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-conditional-loops-and-local-vars/4")
 2865     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/5")
 2866     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-conditional-loops-and-local-vars/6")
 2867     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/7")
 2868     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-conditional-loops-and-local-vars/8")
 2869     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-conditional-loops-and-local-vars/9")
 2870     (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")
 2871     (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")
 2872     (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")
 2873     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-conditional-loops-and-local-vars/13")
 2874     (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")
 2875     (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")
 2876     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-conditional-loops-and-local-vars/16")
 2877     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/17")
 2878     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-conditional-loops-and-local-vars/18")
 2879     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/19")
 2880     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-conditional-loops-and-local-vars/20")
 2881     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-conditional-loops-and-local-vars/21")
 2882     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-conditional-loops-and-local-vars/22")
 2883     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-conditional-loops-and-local-vars/23")
 2884     # . epilogue
 2885     89/<- %esp 5/r32/ebp
 2886     5d/pop-to-ebp
 2887     c3/return
 2888 
 2889 test-convert-function-with-unconditional-loops-and-local-vars:
 2890     # An unconditional 'loop' after a 'var' in a block is emitted _after_ the
 2891     # regular block cleanup. Any instructions after 'loop' are dead and
 2892     # therefore skipped.
 2893     # . prologue
 2894     55/push-ebp
 2895     89/<- %ebp 4/r32/esp
 2896     # setup
 2897     (clear-stream _test-input-stream)
 2898     (clear-stream $_test-input-buffered-file->buffer)
 2899     (clear-stream _test-output-stream)
 2900     (clear-stream $_test-output-buffered-file->buffer)
 2901     #
 2902     (write _test-input-stream "fn foo {\n")
 2903     (write _test-input-stream "  {\n")
 2904     (write _test-input-stream "    var x: int\n")
 2905     (write _test-input-stream "    loop\n")
 2906     (write _test-input-stream "    increment x\n")
 2907     (write _test-input-stream "  }\n")
 2908     (write _test-input-stream "}\n")
 2909     # convert
 2910     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2911     (flush _test-output-buffered-file)
 2912 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2918     # check output
 2919     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-loops-and-local-vars/0")
 2920     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/1")
 2921     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-loops-and-local-vars/2")
 2922     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/3")
 2923     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/4")
 2924     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/5")
 2925     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/6")
 2926     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/7")
 2927     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-loops-and-local-vars/8")
 2928     (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")
 2929     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-unconditional-loops-and-local-vars/10")
 2930     # not emitted:                                           ff 0/subop/increment *(ebp+0xfffffffc)
 2931     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/11")
 2932     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/12")
 2933     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/13")
 2934     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/14")
 2935     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/15")
 2936     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/16")
 2937     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-loops-and-local-vars/17")
 2938     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-loops-and-local-vars/18")
 2939     # . epilogue
 2940     89/<- %esp 5/r32/ebp
 2941     5d/pop-to-ebp
 2942     c3/return
 2943 
 2944 test-convert-function-with-branches-and-loops-and-local-vars:
 2945     # . prologue
 2946     55/push-ebp
 2947     89/<- %ebp 4/r32/esp
 2948     # setup
 2949     (clear-stream _test-input-stream)
 2950     (clear-stream $_test-input-buffered-file->buffer)
 2951     (clear-stream _test-output-stream)
 2952     (clear-stream $_test-output-buffered-file->buffer)
 2953     #
 2954     (write _test-input-stream "fn foo {\n")
 2955     (write _test-input-stream "  {\n")
 2956     (write _test-input-stream "    var x: int\n")
 2957     (write _test-input-stream "    break-if->=\n")
 2958     (write _test-input-stream "    increment x\n")
 2959     (write _test-input-stream "    loop\n")
 2960     (write _test-input-stream "  }\n")
 2961     (write _test-input-stream "}\n")
 2962     # convert
 2963     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2964     (flush _test-output-buffered-file)
 2965 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2971     # check output
 2972     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-loops-and-local-vars/0")
 2973     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/1")
 2974     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-loops-and-local-vars/2")
 2975     (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")
 2976     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/4")
 2977     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/5")
 2978     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/6")
 2979     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/7")
 2980     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-loops-and-local-vars/8")
 2981     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/9")
 2982     (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")
 2983     (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")
 2984     (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")
 2985     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/13")
 2986     (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")
 2987     (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")
 2988     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-and-loops-and-local-vars/16")
 2989     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/17")
 2990     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/18")
 2991     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/19")
 2992     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/20")
 2993     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/21")
 2994     (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")
 2995     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-loops-and-local-vars/23")
 2996     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-loops-and-local-vars/24")
 2997     # . epilogue
 2998     89/<- %esp 5/r32/ebp
 2999     5d/pop-to-ebp
 3000     c3/return
 3001 
 3002 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars:
 3003     # . prologue
 3004     55/push-ebp
 3005     89/<- %ebp 4/r32/esp
 3006     # setup
 3007     (clear-stream _test-input-stream)
 3008     (clear-stream $_test-input-buffered-file->buffer)
 3009     (clear-stream _test-output-stream)
 3010     (clear-stream $_test-output-buffered-file->buffer)
 3011     #
 3012     (write _test-input-stream "fn foo {\n")
 3013     (write _test-input-stream "  a: {\n")
 3014     (write _test-input-stream "    var x: int\n")
 3015     (write _test-input-stream "    {\n")
 3016     (write _test-input-stream "      var y: int\n")
 3017     (write _test-input-stream "      break-if->= a\n")
 3018     (write _test-input-stream "      increment x\n")
 3019     (write _test-input-stream "      loop\n")
 3020     (write _test-input-stream "    }\n")
 3021     (write _test-input-stream "  }\n")
 3022     (write _test-input-stream "}\n")
 3023     # convert
 3024     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3025     (flush _test-output-buffered-file)
 3026 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3032     # check output
 3033     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/0")
 3034     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/1")
 3035     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/2")
 3036     (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")
 3037     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/4")
 3038     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/5")
 3039     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/6")
 3040     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/7")
 3041     (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")
 3042     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/9")
 3043     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/10")
 3044     (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")
 3045     (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/12")
 3046     (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")
 3047     (check-next-stream-line-equal _test-output-stream "          81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/14")
 3048     (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")
 3049     (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")
 3050     (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/17")
 3051     (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")
 3052     (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")
 3053     (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")
 3054     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/21")
 3055     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/22")
 3056     (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")
 3057     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/24")
 3058     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/25")
 3059     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/26")
 3060     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/27")
 3061     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/28")
 3062     (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")
 3063     (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")
 3064     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/31")
 3065     # . epilogue
 3066     89/<- %esp 5/r32/ebp
 3067     5d/pop-to-ebp
 3068     c3/return
 3069 
 3070 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2:
 3071     # . prologue
 3072     55/push-ebp
 3073     89/<- %ebp 4/r32/esp
 3074     # setup
 3075     (clear-stream _test-input-stream)
 3076     (clear-stream $_test-input-buffered-file->buffer)
 3077     (clear-stream _test-output-stream)
 3078     (clear-stream $_test-output-buffered-file->buffer)
 3079     # non-local conditional branch from a block without a local variable,
 3080     # unwinding a local on the stack
 3081     (write _test-input-stream "fn foo {\n")
 3082     (write _test-input-stream "  a: {\n")
 3083     (write _test-input-stream "    var x: int\n")
 3084     (write _test-input-stream "    {\n")
 3085     (write _test-input-stream "      break-if->= a\n")
 3086     (write _test-input-stream "    }\n")
 3087     (write _test-input-stream "  }\n")
 3088     (write _test-input-stream "}\n")
 3089     # convert
 3090     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3091     (flush _test-output-buffered-file)
 3092 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3098     # check output
 3099     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/0")
 3100     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/1")
 3101     (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")
 3102     (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")
 3103     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/4")
 3104     (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")
 3105     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/6")
 3106     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/7")
 3107     (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")
 3108     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/9")
 3109     (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")
 3110     (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/11")
 3111     (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")
 3112     (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")
 3113     (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")
 3114     (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/15")
 3115     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/16")
 3116     (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")
 3117     (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")
 3118     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/19")
 3119     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/20")
 3120     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/21")
 3121     (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")
 3122     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/23")
 3123     (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")
 3124     (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")
 3125     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/26")
 3126     # . epilogue
 3127     89/<- %esp 5/r32/ebp
 3128     5d/pop-to-ebp
 3129     c3/return
 3130 
 3131 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3:
 3132     # . prologue
 3133     55/push-ebp
 3134     89/<- %ebp 4/r32/esp
 3135     # setup
 3136     (clear-stream _test-input-stream)
 3137     (clear-stream $_test-input-buffered-file->buffer)
 3138     (clear-stream _test-output-stream)
 3139     (clear-stream $_test-output-buffered-file->buffer)
 3140     # non-local unconditional branch from a block without a local variable,
 3141     # unwinding a local on the stack
 3142     (write _test-input-stream "fn foo {\n")
 3143     (write _test-input-stream "  a: {\n")
 3144     (write _test-input-stream "    var x: int\n")
 3145     (write _test-input-stream "    {\n")
 3146     (write _test-input-stream "      break a\n")
 3147     (write _test-input-stream "    }\n")
 3148     (write _test-input-stream "  }\n")
 3149     (write _test-input-stream "}\n")
 3150     # convert
 3151     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3152     (flush _test-output-buffered-file)
 3153 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3159     # check output
 3160     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/0")
 3161     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/1")
 3162     (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")
 3163     (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")
 3164     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/4")
 3165     (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")
 3166     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/6")
 3167     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/7")
 3168     (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")
 3169     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/9")
 3170     (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")
 3171     (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")
 3172     (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")
 3173     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/14")
 3174     (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")
 3175     (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")
 3176     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/17")
 3177     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/18")
 3178     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/19")
 3179     (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")
 3180     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/21")
 3181     (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")
 3182     (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")
 3183     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/24")
 3184     # . epilogue
 3185     89/<- %esp 5/r32/ebp
 3186     5d/pop-to-ebp
 3187     c3/return
 3188 
 3189 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4:
 3190     # . prologue
 3191     55/push-ebp
 3192     89/<- %ebp 4/r32/esp
 3193     # setup
 3194     (clear-stream _test-input-stream)
 3195     (clear-stream $_test-input-buffered-file->buffer)
 3196     (clear-stream _test-output-stream)
 3197     (clear-stream $_test-output-buffered-file->buffer)
 3198     #
 3199     (write _test-input-stream "fn foo {\n")
 3200     (write _test-input-stream "  a: {\n")
 3201     (write _test-input-stream "    var x/esi: int <- copy 0\n")
 3202     (write _test-input-stream "    {\n")
 3203     (write _test-input-stream "      break a\n")
 3204     (write _test-input-stream "    }\n")
 3205     (write _test-input-stream "  }\n")
 3206     (write _test-input-stream "}\n")
 3207     # convert
 3208     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3209     (flush _test-output-buffered-file)
 3210 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3216     # check output
 3217     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/0")
 3218     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/1")
 3219     (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")
 3220     (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")
 3221     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/4")
 3222     (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")
 3223     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/6")
 3224     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/7")
 3225     (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")
 3226     (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")
 3227     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/10")
 3228     (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")
 3229     (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")
 3230     (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")
 3231     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/14")
 3232     (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")
 3233     (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")
 3234     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/17")
 3235     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/18")
 3236     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/19")
 3237     (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")
 3238     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/21")
 3239     (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")
 3240     (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")
 3241     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/24")
 3242     # . epilogue
 3243     89/<- %esp 5/r32/ebp
 3244     5d/pop-to-ebp
 3245     c3/return
 3246 
 3247 test-convert-function-with-nonlocal-unconditional-break-and-local-vars:
 3248     # . prologue
 3249     55/push-ebp
 3250     89/<- %ebp 4/r32/esp
 3251     # setup
 3252     (clear-stream _test-input-stream)
 3253     (clear-stream $_test-input-buffered-file->buffer)
 3254     (clear-stream _test-output-stream)
 3255     (clear-stream $_test-output-buffered-file->buffer)
 3256     #
 3257     (write _test-input-stream "fn foo {\n")
 3258     (write _test-input-stream "  a: {\n")
 3259     (write _test-input-stream "    var x: int\n")
 3260     (write _test-input-stream "    {\n")
 3261     (write _test-input-stream "      var y: int\n")
 3262     (write _test-input-stream "      break a\n")
 3263     (write _test-input-stream "      increment x\n")
 3264     (write _test-input-stream "    }\n")
 3265     (write _test-input-stream "  }\n")
 3266     (write _test-input-stream "}\n")
 3267     # convert
 3268     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3269     (flush _test-output-buffered-file)
 3270 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3276     # check output
 3277     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/0")
 3278     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/1")
 3279     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/2")
 3280     (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")
 3281     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/4")
 3282     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/5")
 3283     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/6")
 3284     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/7")
 3285     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/8")
 3286     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/9")
 3287     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/10")
 3288     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/11")
 3289     (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")
 3290     (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")
 3291     (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")
 3292     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/15")
 3293     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/16")
 3294     (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")
 3295     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/18")
 3296     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/19")
 3297     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/20")
 3298     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/21")
 3299     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/22")
 3300     (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")
 3301     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/24")
 3302     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/25")
 3303     # . epilogue
 3304     89/<- %esp 5/r32/ebp
 3305     5d/pop-to-ebp
 3306     c3/return
 3307 
 3308 test-convert-function-with-unconditional-break-and-local-vars:
 3309     # . prologue
 3310     55/push-ebp
 3311     89/<- %ebp 4/r32/esp
 3312     # setup
 3313     (clear-stream _test-input-stream)
 3314     (clear-stream $_test-input-buffered-file->buffer)
 3315     (clear-stream _test-output-stream)
 3316     (clear-stream $_test-output-buffered-file->buffer)
 3317     #
 3318     (write _test-input-stream "fn foo {\n")
 3319     (write _test-input-stream "  {\n")
 3320     (write _test-input-stream "    var x: int\n")
 3321     (write _test-input-stream "    {\n")
 3322     (write _test-input-stream "      var y: int\n")
 3323     (write _test-input-stream "      break\n")
 3324     (write _test-input-stream "      increment x\n")
 3325     (write _test-input-stream "    }\n")
 3326     (write _test-input-stream "  }\n")
 3327     (write _test-input-stream "}\n")
 3328     # convert
 3329     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3330     (flush _test-output-buffered-file)
 3331 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3337     # check output
 3338     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-break-and-local-vars/0")
 3339     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-break-and-local-vars/1")
 3340     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-break-and-local-vars/2")
 3341     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-break-and-local-vars/3")
 3342     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-break-and-local-vars/4")
 3343     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/5")
 3344     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-break-and-local-vars/6")
 3345     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/7")
 3346     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-break-and-local-vars/8")
 3347     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-unconditional-break-and-local-vars/9")
 3348     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/10")
 3349     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/11")
 3350     (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")
 3351     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-unconditional-break-and-local-vars/13")
 3352     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/14")
 3353     (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")
 3354     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-break-and-local-vars/16")
 3355     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/17")
 3356     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-break-and-local-vars/18")
 3357     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/19")
 3358     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-break-and-local-vars/20")
 3359     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-break-and-local-vars/21")
 3360     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-break-and-local-vars/22")
 3361     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-break-and-local-vars/23")
 3362     # . epilogue
 3363     89/<- %esp 5/r32/ebp
 3364     5d/pop-to-ebp
 3365     c3/return
 3366 
 3367 test-convert-function-with-nonlocal-unconditional-loop-and-local-vars:
 3368     # . prologue
 3369     55/push-ebp
 3370     89/<- %ebp 4/r32/esp
 3371     # setup
 3372     (clear-stream _test-input-stream)
 3373     (clear-stream $_test-input-buffered-file->buffer)
 3374     (clear-stream _test-output-stream)
 3375     (clear-stream $_test-output-buffered-file->buffer)
 3376     #
 3377     (write _test-input-stream "fn foo {\n")
 3378     (write _test-input-stream "  a: {\n")
 3379     (write _test-input-stream "    var x: int\n")
 3380     (write _test-input-stream "    {\n")
 3381     (write _test-input-stream "      var y: int\n")
 3382     (write _test-input-stream "      loop a\n")
 3383     (write _test-input-stream "      increment x\n")
 3384     (write _test-input-stream "    }\n")
 3385     (write _test-input-stream "  }\n")
 3386     (write _test-input-stream "}\n")
 3387     # convert
 3388     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3389     (flush _test-output-buffered-file)
 3390 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3396     # check output
 3397     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/0")
 3398     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/1")
 3399     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/2")
 3400     (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")
 3401     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/4")
 3402     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/5")
 3403     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/6")
 3404     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/7")
 3405     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/8")
 3406     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/9")
 3407     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/10")
 3408     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/11")
 3409     (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")
 3410     (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")
 3411     (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")
 3412     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/15")
 3413     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/16")
 3414     (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")
 3415     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/18")
 3416     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/19")
 3417     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/20")
 3418     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/21")
 3419     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/22")
 3420     (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")
 3421     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/24")
 3422     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/25")
 3423     # . epilogue
 3424     89/<- %esp 5/r32/ebp
 3425     5d/pop-to-ebp
 3426     c3/return
 3427 
 3428 test-convert-function-with-local-array-var-in-mem:
 3429     # . prologue
 3430     55/push-ebp
 3431     89/<- %ebp 4/r32/esp
 3432     # setup
 3433     (clear-stream _test-input-stream)
 3434     (clear-stream $_test-input-buffered-file->buffer)
 3435     (clear-stream _test-output-stream)
 3436     (clear-stream $_test-output-buffered-file->buffer)
 3437     #
 3438     (write _test-input-stream "fn foo {\n")
 3439     (write _test-input-stream "  var x: (array int 3)\n")
 3440     (write _test-input-stream "}\n")
 3441     # convert
 3442     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3443     (flush _test-output-buffered-file)
 3444 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3450     # check output
 3451     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-array-var-in-mem/0")
 3452     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-array-var-in-mem/1")
 3453     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-array-var-in-mem/2")
 3454     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-array-var-in-mem/3")
 3455     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-array-var-in-mem/4")
 3456     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-array-var-in-mem/5")
 3457     # define x
 3458     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-function-with-local-array-var-in-mem/7")
 3459     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-function-with-local-array-var-in-mem/8")
 3460     # reclaim x
 3461     (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")
 3462     #
 3463     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-array-var-in-mem/10")
 3464     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-array-var-in-mem/11")
 3465     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-array-var-in-mem/12")
 3466     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-array-var-in-mem/13")
 3467     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-array-var-in-mem/14")
 3468     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-array-var-in-mem/15")
 3469     # . epilogue
 3470     89/<- %esp 5/r32/ebp
 3471     5d/pop-to-ebp
 3472     c3/return
 3473 
 3474 # special-case for size(byte) when allocating array
 3475 test-convert-function-with-local-array-of-bytes-in-mem:
 3476     # . prologue
 3477     55/push-ebp
 3478     89/<- %ebp 4/r32/esp
 3479     # setup
 3480     (clear-stream _test-input-stream)
 3481     (clear-stream $_test-input-buffered-file->buffer)
 3482     (clear-stream _test-output-stream)
 3483     (clear-stream $_test-output-buffered-file->buffer)
 3484     #
 3485     (write _test-input-stream "fn foo {\n")
 3486     (write _test-input-stream "  var x: (array byte 3)\n")
 3487     (write _test-input-stream "}\n")
 3488     # convert
 3489     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3490     (flush _test-output-buffered-file)
 3491 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3497     # check output
 3498     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-array-of-bytes-in-mem/0")
 3499     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-array-of-bytes-in-mem/1")
 3500     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-array-of-bytes-in-mem/2")
 3501     (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")
 3502     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-array-of-bytes-in-mem/4")
 3503     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-array-of-bytes-in-mem/5")
 3504     # define x
 3505     (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")
 3506     (check-next-stream-line-equal _test-output-stream "    68/push 0x00000003/imm32"  "F - test-convert-function-with-local-array-of-bytes-in-mem/8")
 3507     # reclaim x
 3508     (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")
 3509     #
 3510     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-array-of-bytes-in-mem/10")
 3511     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-array-of-bytes-in-mem/11")
 3512     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-array-of-bytes-in-mem/12")
 3513     (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")
 3514     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-array-of-bytes-in-mem/14")
 3515     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-array-of-bytes-in-mem/15")
 3516     # . epilogue
 3517     89/<- %esp 5/r32/ebp
 3518     5d/pop-to-ebp
 3519     c3/return
 3520 
 3521 test-convert-address:
 3522     # . prologue
 3523     55/push-ebp
 3524     89/<- %ebp 4/r32/esp
 3525     # setup
 3526     (clear-stream _test-input-stream)
 3527     (clear-stream $_test-input-buffered-file->buffer)
 3528     (clear-stream _test-output-stream)
 3529     (clear-stream $_test-output-buffered-file->buffer)
 3530     #
 3531     (write _test-input-stream "fn foo {\n")
 3532     (write _test-input-stream "  var a: int\n")
 3533     (write _test-input-stream "  var b/eax: (addr int) <- address a\n")
 3534     (write _test-input-stream "}\n")
 3535     # convert
 3536     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3537     (flush _test-output-buffered-file)
 3538 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3544     # check output
 3545     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-address/0")
 3546     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-address/1")
 3547     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-address/2")
 3548     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-address/3")
 3549     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-address/4")
 3550     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-address/5")
 3551     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-address/6")
 3552     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-address/7")
 3553     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000000/r32"  "F - test-convert-address/8")
 3554     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-address/9")
 3555     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-address/10")
 3556     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-address/11")
 3557     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-address/12")
 3558     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-address/13")
 3559     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-address/14")
 3560     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-address/15")
 3561     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-address/16")
 3562     # . epilogue
 3563     89/<- %esp 5/r32/ebp
 3564     5d/pop-to-ebp
 3565     c3/return
 3566 
 3567 test-convert-length-of-array:
 3568     # . prologue
 3569     55/push-ebp
 3570     89/<- %ebp 4/r32/esp
 3571     # setup
 3572     (clear-stream _test-input-stream)
 3573     (clear-stream $_test-input-buffered-file->buffer)
 3574     (clear-stream _test-output-stream)
 3575     (clear-stream $_test-output-buffered-file->buffer)
 3576     #
 3577     (write _test-input-stream "fn foo a: (addr array int) {\n")
 3578     (write _test-input-stream "  var b/eax: (addr array int) <- copy a\n")
 3579     (write _test-input-stream "  var c/eax: int <- length b\n")
 3580     (write _test-input-stream "}\n")
 3581     # convert
 3582     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3583     (flush _test-output-buffered-file)
 3584 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3590     # check output
 3591     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array/0")
 3592     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array/1")
 3593     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array/2")
 3594     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array/3")
 3595     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array/4")
 3596     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array/5")
 3597     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array/6")
 3598     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-length-of-array/7")
 3599     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array/8")
 3600     (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array/9")
 3601     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array/10")
 3602     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array/11")
 3603     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array/12")
 3604     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array/13")
 3605     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array/14")
 3606     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array/15")
 3607     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array/16")
 3608     # . epilogue
 3609     89/<- %esp 5/r32/ebp
 3610     5d/pop-to-ebp
 3611     c3/return
 3612 
 3613 # special-case for size(byte) when computing array length
 3614 test-convert-length-of-array-of-bytes:
 3615     # . prologue
 3616     55/push-ebp
 3617     89/<- %ebp 4/r32/esp
 3618     # setup
 3619     (clear-stream _test-input-stream)
 3620     (clear-stream $_test-input-buffered-file->buffer)
 3621     (clear-stream _test-output-stream)
 3622     (clear-stream $_test-output-buffered-file->buffer)
 3623     #
 3624     (write _test-input-stream "fn foo a: (addr array byte) {\n")
 3625     (write _test-input-stream "  var b/eax: (addr array byte) <- copy a\n")
 3626     (write _test-input-stream "  var c/eax: int <- length b\n")
 3627     (write _test-input-stream "}\n")
 3628     # convert
 3629     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3630     (flush _test-output-buffered-file)
 3631 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3637     # check output
 3638     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-bytes/0")
 3639     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-bytes/1")
 3640     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-bytes/2")
 3641     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-bytes/3")
 3642     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-bytes/4")
 3643     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-bytes/5")
 3644     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-bytes/6")
 3645     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-length-of-array-of-bytes/7")
 3646     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-bytes/8")
 3647     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-bytes/9")
 3648     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-bytes/10")
 3649     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-bytes/11")
 3650     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-bytes/12")
 3651     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-bytes/13")
 3652     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-bytes/14")
 3653     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-bytes/15")
 3654     # . epilogue
 3655     89/<- %esp 5/r32/ebp
 3656     5d/pop-to-ebp
 3657     c3/return
 3658 
 3659 test-convert-length-of-array-on-stack:
 3660     # . prologue
 3661     55/push-ebp
 3662     89/<- %ebp 4/r32/esp
 3663     # setup
 3664     (clear-stream _test-input-stream)
 3665     (clear-stream $_test-input-buffered-file->buffer)
 3666     (clear-stream _test-output-stream)
 3667     (clear-stream $_test-output-buffered-file->buffer)
 3668     #
 3669     (write _test-input-stream "fn foo {\n")
 3670     (write _test-input-stream "  var a: (array int 3)\n")
 3671     (write _test-input-stream "  var b/eax: int <- length a\n")
 3672     (write _test-input-stream "}\n")
 3673     # convert
 3674     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3675     (flush _test-output-buffered-file)
 3676 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3682     # check output
 3683     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-on-stack/0")
 3684     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-on-stack/1")
 3685     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-on-stack/2")
 3686     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-on-stack/3")
 3687     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-on-stack/4")
 3688     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-on-stack/5")
 3689     # define x
 3690     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-length-of-array-on-stack/6")
 3691     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-length-of-array-on-stack/7")
 3692     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-on-stack/8")
 3693     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0xfffffff0) 0x00000000/r32"  "F - test-convert-length-of-array-on-stack/9")
 3694     (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array-on-stack/10")
 3695     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-on-stack/11")
 3696     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"  "F - test-convert-length-of-array-on-stack/12")
 3697     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-on-stack/13")
 3698     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-on-stack/14")
 3699     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-on-stack/15")
 3700     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-on-stack/16")
 3701     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-on-stack/17")
 3702     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-on-stack/18")
 3703     # . epilogue
 3704     89/<- %esp 5/r32/ebp
 3705     5d/pop-to-ebp
 3706     c3/return
 3707 
 3708 test-reg-var-def-with-read-of-same-register:
 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     (clear-stream _test-error-stream)
 3718     (clear-stream $_test-error-buffered-file->buffer)
 3719     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)  # bytes of args in call to convert-mu
 3720     68/push 0/imm32
 3721     68/push 0/imm32
 3722     89/<- %edx 4/r32/esp
 3723     (tailor-exit-descriptor %edx 0x10)
 3724     #
 3725     (write _test-input-stream "fn foo {\n")
 3726     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 3727     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 3728     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 3729     (write _test-input-stream "}\n")
 3730     # convert
 3731     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 3732     # registers except esp could be clobbered at this point (though they shouldn't be)
 3733     # restore ed
 3734     89/<- %edx 4/r32/esp
 3735     (flush _test-output-buffered-file)
 3736     (flush _test-error-buffered-file)
 3737 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3743     (check-stream-equal _test-error-stream  ""  "F - test-reg-var-def-with-read-of-same-register: error stream should be empty")
 3744     # check output
 3745     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-reg-var-def-with-read-of-same-register/0")
 3746     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-reg-var-def-with-read-of-same-register/1")
 3747     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-reg-var-def-with-read-of-same-register/2")
 3748     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-reg-var-def-with-read-of-same-register/3")
 3749     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-reg-var-def-with-read-of-same-register/4")
 3750     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-reg-var-def-with-read-of-same-register/5")
 3751     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-reg-var-def-with-read-of-same-register/6")
 3752     (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")
 3753     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-reg-var-def-with-read-of-same-register/8")
 3754     (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")
 3755     (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")
 3756     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-reg-var-def-with-read-of-same-register/13")
 3757     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-reg-var-def-with-read-of-same-register/14")
 3758     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-reg-var-def-with-read-of-same-register/15")
 3759     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-reg-var-def-with-read-of-same-register/16")
 3760     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-reg-var-def-with-read-of-same-register/17")
 3761     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-reg-var-def-with-read-of-same-register/18")
 3762     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-reg-var-def-with-read-of-same-register/19")
 3763     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-reg-var-def-with-read-of-same-register/20")
 3764     # don't restore from ebp
 3765     81 0/subop/add %esp 8/imm32
 3766     # . epilogue
 3767     5d/pop-to-ebp
 3768     c3/return
 3769 
 3770 test-convert-index-into-array:
 3771     # . prologue
 3772     55/push-ebp
 3773     89/<- %ebp 4/r32/esp
 3774     # setup
 3775     (clear-stream _test-input-stream)
 3776     (clear-stream $_test-input-buffered-file->buffer)
 3777     (clear-stream _test-output-stream)
 3778     (clear-stream $_test-output-buffered-file->buffer)
 3779     #
 3780     (write _test-input-stream "fn foo {\n")
 3781     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 3782     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 3783     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 3784     (write _test-input-stream "}\n")
 3785     # convert
 3786     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3787     (flush _test-output-buffered-file)
 3788 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3794     # check output
 3795     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array/0")
 3796     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array/1")
 3797     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array/2")
 3798     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array/3")
 3799     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array/4")
 3800     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array/5")
 3801     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array/6")
 3802     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array/7")
 3803     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array/8")
 3804     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array/9")
 3805     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx<<0x00000002 + 4) 0x00000000/r32"  "F - test-convert-index-into-array/10")
 3806     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array/11")
 3807     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array/12")
 3808     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array/13")
 3809     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array/14")
 3810     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array/15")
 3811     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array/16")
 3812     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array/17")
 3813     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array/18")
 3814     # . epilogue
 3815     89/<- %esp 5/r32/ebp
 3816     5d/pop-to-ebp
 3817     c3/return
 3818 
 3819 test-convert-index-into-array-of-bytes:
 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 byte) <- copy 0\n")
 3831     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 3832     (write _test-input-stream "  var x/eax: (addr byte) <- 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-of-bytes/0")
 3845     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes/1")
 3846     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes/2")
 3847     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes/3")
 3848     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes/4")
 3849     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes/5")
 3850     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes/6")
 3851     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-of-bytes/7")
 3852     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes/8")
 3853     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-of-bytes/9")
 3854     (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")
 3855     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes/13")
 3856     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes/14")
 3857     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes/15")
 3858     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes/16")
 3859     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes/17")
 3860     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes/18")
 3861     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes/19")
 3862     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes/20")
 3863     # . epilogue
 3864     89/<- %esp 5/r32/ebp
 3865     5d/pop-to-ebp
 3866     c3/return
 3867 
 3868 test-convert-index-into-array-with-literal:
 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 int) <- copy 0\n")
 3880     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
 3881     (write _test-input-stream "}\n")
 3882     # convert
 3883     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3884     (flush _test-output-buffered-file)
 3885 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3891     # check output
 3892     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-with-literal/0")
 3893     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-with-literal/1")
 3894     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-with-literal/2")
 3895     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-with-literal/3")
 3896     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-with-literal/4")
 3897     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-with-literal/5")
 3898     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-with-literal/6")
 3899     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-with-literal/7")
 3900                                                                                  # 2 * 4 bytes/elem + 4 bytes for size = offset 12
 3901     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x0000000c) 0x00000000/r32"  "F - test-convert-index-into-array-with-literal/8")
 3902     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-with-literal/9")
 3903     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-with-literal/10")
 3904     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-with-literal/11")
 3905     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-with-literal/12")
 3906     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-with-literal/13")
 3907     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-with-literal/14")
 3908     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-with-literal/15")
 3909     # . epilogue
 3910     89/<- %esp 5/r32/ebp
 3911     5d/pop-to-ebp
 3912     c3/return
 3913 
 3914 test-convert-index-into-array-of-bytes-with-literal:
 3915     # . prologue
 3916     55/push-ebp
 3917     89/<- %ebp 4/r32/esp
 3918     # setup
 3919     (clear-stream _test-input-stream)
 3920     (clear-stream $_test-input-buffered-file->buffer)
 3921     (clear-stream _test-output-stream)
 3922     (clear-stream $_test-output-buffered-file->buffer)
 3923     #
 3924     (write _test-input-stream "fn foo {\n")
 3925     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 3926     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, 2\n")
 3927     (write _test-input-stream "}\n")
 3928     # convert
 3929     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3930     (flush _test-output-buffered-file)
 3931 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3937     # check output
 3938     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-with-literal/0")
 3939     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-with-literal/1")
 3940     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-with-literal/2")
 3941     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-with-literal/3")
 3942     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-with-literal/4")
 3943     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-with-literal/5")
 3944     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-with-literal/6")
 3945     (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")
 3946                                                                                  # 2 * 1 byte/elem + 4 bytes for size = offset 6
 3947     (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")
 3948     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-with-literal/9")
 3949     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-with-literal/10")
 3950     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-with-literal/11")
 3951     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-with-literal/12")
 3952     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-with-literal/13")
 3953     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-with-literal/14")
 3954     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-with-literal/15")
 3955     # . epilogue
 3956     89/<- %esp 5/r32/ebp
 3957     5d/pop-to-ebp
 3958     c3/return
 3959 
 3960 test-convert-index-into-array-on-stack:
 3961     # . prologue
 3962     55/push-ebp
 3963     89/<- %ebp 4/r32/esp
 3964     # setup
 3965     (clear-stream _test-input-stream)
 3966     (clear-stream $_test-input-buffered-file->buffer)
 3967     (clear-stream _test-output-stream)
 3968     (clear-stream $_test-output-buffered-file->buffer)
 3969     #
 3970     (write _test-input-stream "fn foo {\n")
 3971     (write _test-input-stream "  var arr: (array int 3)\n")
 3972     (write _test-input-stream "  var idx/eax: int <- copy 2\n")
 3973     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 3974     (write _test-input-stream "}\n")
 3975     # convert
 3976     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3977     (flush _test-output-buffered-file)
 3978 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3984     # check output
 3985     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack/0")
 3986     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack/1")
 3987     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack/2")
 3988     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack/3")
 3989     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack/4")
 3990     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack/5")
 3991     # var arr
 3992     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack/6")
 3993     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack/7")
 3994     # var idx
 3995     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack/8")
 3996     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 2/imm32"                  "F - test-convert-index-into-array-on-stack/9")
 3997     # var x is at (ebp-0x10) + idx<<2 + 4 = ebp + idx<<2 - 0xc
 3998     (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")
 3999     # reclaim idx
 4000     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack/11")
 4001     # reclaim arr
 4002     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"    "F - test-convert-index-into-array-on-stack/12")
 4003     #
 4004     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack/13")
 4005     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack/14")
 4006     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack/15")
 4007     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack/16")
 4008     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack/17")
 4009     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack/18")
 4010     # . epilogue
 4011     89/<- %esp 5/r32/ebp
 4012     5d/pop-to-ebp
 4013     c3/return
 4014 
 4015 test-convert-index-into-array-on-stack-with-literal:
 4016     # . prologue
 4017     55/push-ebp
 4018     89/<- %ebp 4/r32/esp
 4019     # setup
 4020     (clear-stream _test-input-stream)
 4021     (clear-stream $_test-input-buffered-file->buffer)
 4022     (clear-stream _test-output-stream)
 4023     (clear-stream $_test-output-buffered-file->buffer)
 4024     #
 4025     (write _test-input-stream "fn foo {\n")
 4026     (write _test-input-stream "  var arr: (array int 3)\n")
 4027     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
 4028     (write _test-input-stream "}\n")
 4029     # convert
 4030     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4031     (flush _test-output-buffered-file)
 4032 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4038     # check output
 4039     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack-with-literal/0")
 4040     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack-with-literal/1")
 4041     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack-with-literal/2")
 4042     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack-with-literal/3")
 4043     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack-with-literal/4")
 4044     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack-with-literal/5")
 4045     # var arr
 4046     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack-with-literal/6")
 4047     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack-with-literal/7")
 4048     # var x
 4049     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack-with-literal/8")
 4050     # x is at (ebp-0x10) + 4 + 2*4 = ebp-4
 4051     (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")
 4052     # reclaim x
 4053     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack-with-literal/10")
 4054     # reclaim arr
 4055     (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")
 4056     #
 4057     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack-with-literal/12")
 4058     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack-with-literal/13")
 4059     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack-with-literal/14")
 4060     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack-with-literal/15")
 4061     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack-with-literal/16")
 4062     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack-with-literal/17")
 4063     # . epilogue
 4064     89/<- %esp 5/r32/ebp
 4065     5d/pop-to-ebp
 4066     c3/return
 4067 
 4068 test-convert-index-into-array-of-bytes-on-stack-with-literal:
 4069     # . prologue
 4070     55/push-ebp
 4071     89/<- %ebp 4/r32/esp
 4072     # setup
 4073     (clear-stream _test-input-stream)
 4074     (clear-stream $_test-input-buffered-file->buffer)
 4075     (clear-stream _test-output-stream)
 4076     (clear-stream $_test-output-buffered-file->buffer)
 4077     #
 4078     (write _test-input-stream "fn foo {\n")
 4079     (write _test-input-stream "  var arr: (array byte 3)\n")
 4080     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, 2\n")
 4081     (write _test-input-stream "}\n")
 4082     # convert
 4083     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4084     (flush _test-output-buffered-file)
 4085 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4091     # check output
 4092     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/0")
 4093     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/1")
 4094     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/2")
 4095     (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")
 4096     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/4")
 4097     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/5")
 4098     # var arr
 4099     (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")
 4100     (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")
 4101     # var x
 4102     (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")
 4103     # x is at (ebp-7) + 4 + 2 = ebp-1
 4104     (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")
 4105     # reclaim x
 4106     (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")
 4107     # reclaim arr
 4108     (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")
 4109     #
 4110     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/12")
 4111     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/13")
 4112     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/14")
 4113     (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")
 4114     (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")
 4115     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/17")
 4116     # . epilogue
 4117     89/<- %esp 5/r32/ebp
 4118     5d/pop-to-ebp
 4119     c3/return
 4120 
 4121 test-convert-index-into-array-using-offset:
 4122     # . prologue
 4123     55/push-ebp
 4124     89/<- %ebp 4/r32/esp
 4125     # setup
 4126     (clear-stream _test-input-stream)
 4127     (clear-stream $_test-input-buffered-file->buffer)
 4128     (clear-stream _test-output-stream)
 4129     (clear-stream $_test-output-buffered-file->buffer)
 4130     #
 4131     (write _test-input-stream "fn foo {\n")
 4132     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4133     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4134     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
 4135     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
 4136     (write _test-input-stream "}\n")
 4137     # convert
 4138     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4139     (flush _test-output-buffered-file)
 4140 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4146     # check output
 4147     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset/0")
 4148     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset/1")
 4149     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset/2")
 4150     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset/3")
 4151     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset/4")
 4152     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset/5")
 4153     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset/6")
 4154     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-using-offset/7")
 4155     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset/8")
 4156     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-using-offset/9")
 4157     (check-next-stream-line-equal _test-output-stream "    69/multiply %ecx 0x00000004/imm32 0x00000001/r32"  "F - test-convert-index-into-array-using-offset/10")
 4158     (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")
 4159     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset/12")
 4160     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset/13")
 4161     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset/14")
 4162     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset/15")
 4163     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset/16")
 4164     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset/17")
 4165     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset/18")
 4166     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset/19")
 4167     # . epilogue
 4168     89/<- %esp 5/r32/ebp
 4169     5d/pop-to-ebp
 4170     c3/return
 4171 
 4172 test-convert-index-into-array-of-bytes-using-offset:
 4173     # . prologue
 4174     55/push-ebp
 4175     89/<- %ebp 4/r32/esp
 4176     # setup
 4177     (clear-stream _test-input-stream)
 4178     (clear-stream $_test-input-buffered-file->buffer)
 4179     (clear-stream _test-output-stream)
 4180     (clear-stream $_test-output-buffered-file->buffer)
 4181     #
 4182     (write _test-input-stream "fn foo {\n")
 4183     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4184     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4185     (write _test-input-stream "  var off/ecx: (offset byte) <- compute-offset arr, idx\n")
 4186     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, off\n")
 4187     (write _test-input-stream "}\n")
 4188     # convert
 4189     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4190     (flush _test-output-buffered-file)
 4191 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4197     # check output
 4198     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-using-offset/0")
 4199     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-using-offset/1")
 4200     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-using-offset/2")
 4201     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-using-offset/3")
 4202     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-using-offset/4")
 4203     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-using-offset/5")
 4204     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-using-offset/6")
 4205     (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")
 4206     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes-using-offset/8")
 4207     (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")
 4208     (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")
 4209     (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")
 4210     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes-using-offset/12")
 4211     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-using-offset/13")
 4212     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-using-offset/14")
 4213     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-using-offset/15")
 4214     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-using-offset/16")
 4215     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-using-offset/17")
 4216     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-using-offset/18")
 4217     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-using-offset/19")
 4218     # . epilogue
 4219     89/<- %esp 5/r32/ebp
 4220     5d/pop-to-ebp
 4221     c3/return
 4222 
 4223 test-convert-index-into-array-using-offset-on-stack:
 4224     # . prologue
 4225     55/push-ebp
 4226     89/<- %ebp 4/r32/esp
 4227     # setup
 4228     (clear-stream _test-input-stream)
 4229     (clear-stream $_test-input-buffered-file->buffer)
 4230     (clear-stream _test-output-stream)
 4231     (clear-stream $_test-output-buffered-file->buffer)
 4232     #
 4233     (write _test-input-stream "fn foo {\n")
 4234     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4235     (write _test-input-stream "  var idx: int\n")
 4236     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
 4237     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
 4238     (write _test-input-stream "}\n")
 4239     # convert
 4240     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4241     (flush _test-output-buffered-file)
 4242 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4248     # check output
 4249     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset-on-stack/0")
 4250     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset-on-stack/1")
 4251     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset-on-stack/2")
 4252     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset-on-stack/3")
 4253     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset-on-stack/4")
 4254     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset-on-stack/5")
 4255     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset-on-stack/6")
 4256     (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")
 4257     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"                         "F - test-convert-index-into-array-using-offset-on-stack/8")
 4258     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset-on-stack/9")
 4259     (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")
 4260     (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")
 4261     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset-on-stack/12")
 4262     (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")
 4263     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset-on-stack/14")
 4264     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset-on-stack/15")
 4265     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset-on-stack/16")
 4266     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset-on-stack/17")
 4267     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset-on-stack/18")
 4268     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset-on-stack/19")
 4269     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset-on-stack/20")
 4270     # . epilogue
 4271     89/<- %esp 5/r32/ebp
 4272     5d/pop-to-ebp
 4273     c3/return
 4274 
 4275 test-convert-index-into-array-of-bytes-using-offset-on-stack:
 4276     # . prologue
 4277     55/push-ebp
 4278     89/<- %ebp 4/r32/esp
 4279     # setup
 4280     (clear-stream _test-input-stream)
 4281     (clear-stream $_test-input-buffered-file->buffer)
 4282     (clear-stream _test-output-stream)
 4283     (clear-stream $_test-output-buffered-file->buffer)
 4284     #
 4285     (write _test-input-stream "fn foo {\n")
 4286     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4287     (write _test-input-stream "  var idx: int\n")
 4288     (write _test-input-stream "  var off/ecx: (offset byte) <- compute-offset arr, idx\n")
 4289     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, off\n")
 4290     (write _test-input-stream "}\n")
 4291     # convert
 4292     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4293     (flush _test-output-buffered-file)
 4294 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4300     # check output
 4301     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/0")
 4302     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/1")
 4303     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/2")
 4304     (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")
 4305     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/4")
 4306     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/5")
 4307     (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")
 4308     (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")
 4309     (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")
 4310     (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")
 4311     (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")
 4312     (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")
 4313     (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")
 4314     (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")
 4315     (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")
 4316     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/15")
 4317     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/16")
 4318     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/17")
 4319     (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")
 4320     (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")
 4321     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/20")
 4322     # . epilogue
 4323     89/<- %esp 5/r32/ebp
 4324     5d/pop-to-ebp
 4325     c3/return
 4326 
 4327 test-convert-function-and-type-definition:
 4328     # . prologue
 4329     55/push-ebp
 4330     89/<- %ebp 4/r32/esp
 4331     # setup
 4332     (clear-stream _test-input-stream)
 4333     (clear-stream $_test-input-buffered-file->buffer)
 4334     (clear-stream _test-output-stream)
 4335     (clear-stream $_test-output-buffered-file->buffer)
 4336     #
 4337     (write _test-input-stream "fn foo a: (addr t) {\n")
 4338     (write _test-input-stream "  var _a/eax: (addr t) <- copy a\n")
 4339     (write _test-input-stream "  var b/ecx: (addr int) <- get _a, x\n")
 4340     (write _test-input-stream "  var c/ecx: (addr int) <- get _a, y\n")
 4341     (write _test-input-stream "}\n")
 4342     (write _test-input-stream "type t {\n")
 4343     (write _test-input-stream "  x: int\n")
 4344     (write _test-input-stream "  y: int\n")
 4345     (write _test-input-stream "}\n")
 4346     # convert
 4347     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4348     (flush _test-output-buffered-file)
 4349 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4355     # check output
 4356     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-and-type-definition/0")
 4357     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-and-type-definition/1")
 4358     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-and-type-definition/2")
 4359     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-and-type-definition/3")
 4360     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-and-type-definition/4")
 4361     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-and-type-definition/5")
 4362     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-function-and-type-definition/6")
 4363     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-and-type-definition/7")
 4364     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-and-type-definition/8")
 4365     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000000) 0x00000001/r32"  "F - test-convert-function-and-type-definition/9")
 4366     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000004) 0x00000001/r32"  "F - test-convert-function-and-type-definition/11")
 4367     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-and-type-definition/13")
 4368     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-convert-function-and-type-definition/14")
 4369     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-and-type-definition/15")
 4370     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-and-type-definition/16")
 4371     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-and-type-definition/17")
 4372     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-and-type-definition/18")
 4373     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-and-type-definition/19")
 4374     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-and-type-definition/20")
 4375     # . epilogue
 4376     89/<- %esp 5/r32/ebp
 4377     5d/pop-to-ebp
 4378     c3/return
 4379 
 4380 test-convert-function-with-local-var-with-user-defined-type:
 4381     # . prologue
 4382     55/push-ebp
 4383     89/<- %ebp 4/r32/esp
 4384     # setup
 4385     (clear-stream _test-input-stream)
 4386     (clear-stream $_test-input-buffered-file->buffer)
 4387     (clear-stream _test-output-stream)
 4388     (clear-stream $_test-output-buffered-file->buffer)
 4389     #
 4390     (write _test-input-stream "fn foo {\n")
 4391     (write _test-input-stream "  var a: t\n")
 4392     (write _test-input-stream "}\n")
 4393     (write _test-input-stream "type t {\n")
 4394     (write _test-input-stream "  x: int\n")
 4395     (write _test-input-stream "  y: int\n")
 4396     (write _test-input-stream "}\n")
 4397     # convert
 4398     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4399     (flush _test-output-buffered-file)
 4400 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4406     # check output
 4407     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-user-defined-type/0")
 4408     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-user-defined-type/1")
 4409     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-user-defined-type/2")
 4410     (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")
 4411     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-user-defined-type/4")
 4412     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-user-defined-type/5")
 4413     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/6")
 4414     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/7")
 4415     (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")
 4416     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-user-defined-type/9")
 4417     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-user-defined-type/10")
 4418     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-user-defined-type/11")
 4419     (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")
 4420     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-with-user-defined-type/13")
 4421     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-user-defined-type/14")
 4422     # . epilogue
 4423     89/<- %esp 5/r32/ebp
 4424     5d/pop-to-ebp
 4425     c3/return
 4426 
 4427 test-convert-function-call-with-arg-of-user-defined-type:
 4428     # . prologue
 4429     55/push-ebp
 4430     89/<- %ebp 4/r32/esp
 4431     # setup
 4432     (clear-stream _test-input-stream)
 4433     (clear-stream $_test-input-buffered-file->buffer)
 4434     (clear-stream _test-output-stream)
 4435     (clear-stream $_test-output-buffered-file->buffer)
 4436     #
 4437     (write _test-input-stream "fn f {\n")
 4438     (write _test-input-stream "  var a: t\n")
 4439     (write _test-input-stream "  foo a\n")
 4440     (write _test-input-stream "}\n")
 4441     (write _test-input-stream "fn foo x: t {\n")
 4442     (write _test-input-stream "}\n")
 4443     (write _test-input-stream "type t {\n")
 4444     (write _test-input-stream "  x: int\n")
 4445     (write _test-input-stream "  y: int\n")
 4446     (write _test-input-stream "}\n")
 4447     # convert
 4448     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4449     (flush _test-output-buffered-file)
 4450 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4456     # check output
 4457     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
 4458     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
 4459     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
 4460     (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")
 4461     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
 4462     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
 4463     # var a: t
 4464     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/6")
 4465     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/7")
 4466     # foo a
 4467     (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")
 4468     #
 4469     (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")
 4470     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
 4471     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
 4472     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
 4473     (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")
 4474     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
 4475     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
 4476     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
 4477     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
 4478     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
 4479     (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")
 4480     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
 4481     (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")
 4482     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
 4483     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
 4484     # . epilogue
 4485     89/<- %esp 5/r32/ebp
 4486     5d/pop-to-ebp
 4487     c3/return
 4488 
 4489 test-convert-function-call-with-arg-of-user-defined-type-register-indirect:
 4490     # . prologue
 4491     55/push-ebp
 4492     89/<- %ebp 4/r32/esp
 4493     # setup
 4494     (clear-stream _test-input-stream)
 4495     (clear-stream $_test-input-buffered-file->buffer)
 4496     (clear-stream _test-output-stream)
 4497     (clear-stream $_test-output-buffered-file->buffer)
 4498     #
 4499     (write _test-input-stream "fn f {\n")
 4500     (write _test-input-stream "  var a/eax: (addr t) <- copy 0\n")
 4501     (write _test-input-stream "  foo *a\n")
 4502     (write _test-input-stream "}\n")
 4503     (write _test-input-stream "fn foo x: t {\n")
 4504     (write _test-input-stream "}\n")
 4505     (write _test-input-stream "type t {\n")
 4506     (write _test-input-stream "  x: int\n")
 4507     (write _test-input-stream "  y: int\n")
 4508     (write _test-input-stream "}\n")
 4509     # convert
 4510     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4511     (flush _test-output-buffered-file)
 4512 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4518     # check output
 4519     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
 4520     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
 4521     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
 4522     (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")
 4523     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
 4524     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
 4525     # var a
 4526     (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")
 4527     (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")
 4528     # foo a
 4529     (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")
 4530     #
 4531     (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")
 4532     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
 4533     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
 4534     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
 4535     (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")
 4536     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
 4537     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
 4538     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
 4539     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
 4540     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
 4541     (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")
 4542     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
 4543     (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")
 4544     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
 4545     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
 4546     # . epilogue
 4547     89/<- %esp 5/r32/ebp
 4548     5d/pop-to-ebp
 4549     c3/return
 4550 
 4551 # we don't have special support for call-by-reference; just explicitly create
 4552 # a new variable with the address of the arg
 4553 test-convert-function-call-with-arg-of-user-defined-type-by-reference:
 4554     # . prologue
 4555     55/push-ebp
 4556     89/<- %ebp 4/r32/esp
 4557     # setup
 4558     (clear-stream _test-input-stream)
 4559     (clear-stream $_test-input-buffered-file->buffer)
 4560     (clear-stream _test-output-stream)
 4561     (clear-stream $_test-output-buffered-file->buffer)
 4562     #
 4563     (write _test-input-stream "fn f {\n")
 4564     (write _test-input-stream "  var a: t\n")
 4565     (write _test-input-stream "  var b/eax: (addr t) <- address a\n")
 4566     (write _test-input-stream "  foo b\n")
 4567     (write _test-input-stream "}\n")
 4568     (write _test-input-stream "fn foo x: (addr t) {\n")
 4569     (write _test-input-stream "  var x/ecx: (addr int) <- copy x\n")
 4570     (write _test-input-stream "  increment *x\n")
 4571     (write _test-input-stream "}\n")
 4572     (write _test-input-stream "type t {\n")
 4573     (write _test-input-stream "  x: int\n")
 4574     (write _test-input-stream "  y: int\n")
 4575     (write _test-input-stream "}\n")
 4576     # convert
 4577     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4578     (flush _test-output-buffered-file)
 4579 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4585     # check output
 4586     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/0")
 4587     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/1")
 4588     (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")
 4589     (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")
 4590     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/4")
 4591     (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")
 4592     # var a: t
 4593     (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")
 4594     (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")
 4595     # var b/eax: (addr t)
 4596     (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")
 4597     (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")
 4598     # foo a
 4599     (check-next-stream-line-equal _test-output-stream "    (foo %eax)"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/10")
 4600     #
 4601     (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")
 4602     (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")
 4603     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/13")
 4604     (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")
 4605     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/15")
 4606     (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")
 4607     (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")
 4608     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/18")
 4609     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/19")
 4610     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/20")
 4611     (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")
 4612     (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")
 4613     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/23")
 4614     (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")
 4615     (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")
 4616     (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")
 4617     (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")
 4618     (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")
 4619     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/29")
 4620     (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")
 4621     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/31")
 4622     (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")
 4623     (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")
 4624     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/34")
 4625     # . epilogue
 4626     89/<- %esp 5/r32/ebp
 4627     5d/pop-to-ebp
 4628     c3/return
 4629 
 4630 test-convert-get-on-local-variable:
 4631     # . prologue
 4632     55/push-ebp
 4633     89/<- %ebp 4/r32/esp
 4634     # setup
 4635     (clear-stream _test-input-stream)
 4636     (clear-stream $_test-input-buffered-file->buffer)
 4637     (clear-stream _test-output-stream)
 4638     (clear-stream $_test-output-buffered-file->buffer)
 4639     #
 4640     (write _test-input-stream "fn foo {\n")
 4641     (write _test-input-stream "  var a: t\n")
 4642     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 4643     (write _test-input-stream "}\n")
 4644     (write _test-input-stream "type t {\n")
 4645     (write _test-input-stream "  x: int\n")
 4646     (write _test-input-stream "  y: int\n")
 4647     (write _test-input-stream "}\n")
 4648     # convert
 4649     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4650     (flush _test-output-buffered-file)
 4651 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4657     # check output
 4658     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-local-variable/0")
 4659     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-local-variable/1")
 4660     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-local-variable/2")
 4661     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-local-variable/3")
 4662     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-local-variable/4")
 4663     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-local-variable/5")
 4664     # var a
 4665     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/6")
 4666     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/7")
 4667     # var c
 4668     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-local-variable/8")
 4669     # get
 4670     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000001/r32"  "F - test-convert-get-on-local-variable/9")
 4671     # reclaim c
 4672     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-local-variable/10")
 4673     # reclaim a
 4674     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000008/imm32"  "F - test-convert-get-on-local-variable/11")
 4675     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-local-variable/12")
 4676     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-local-variable/13")
 4677     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-local-variable/14")
 4678     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-local-variable/15")
 4679     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-local-variable/16")
 4680     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-local-variable/17")
 4681     # . epilogue
 4682     89/<- %esp 5/r32/ebp
 4683     5d/pop-to-ebp
 4684     c3/return
 4685 
 4686 test-convert-get-on-function-argument:
 4687     # . prologue
 4688     55/push-ebp
 4689     89/<- %ebp 4/r32/esp
 4690     # setup
 4691     (clear-stream _test-input-stream)
 4692     (clear-stream $_test-input-buffered-file->buffer)
 4693     (clear-stream _test-output-stream)
 4694     (clear-stream $_test-output-buffered-file->buffer)
 4695     #
 4696     (write _test-input-stream "fn foo a: t {\n")
 4697     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 4698     (write _test-input-stream "}\n")
 4699     (write _test-input-stream "type t {\n")
 4700     (write _test-input-stream "  x: int\n")
 4701     (write _test-input-stream "  y: int\n")
 4702     (write _test-input-stream "}\n")
 4703     # convert
 4704     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4705     (flush _test-output-buffered-file)
 4706 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4712     # check output
 4713     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument/0")
 4714     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument/1")
 4715     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument/2")
 4716     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument/3")
 4717     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument/4")
 4718     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument/5")
 4719     # var c
 4720     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument/6")
 4721     # get
 4722     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0x0000000c) 0x00000001/r32"  "F - test-convert-get-on-function-argument/7")
 4723     # reclaim c
 4724     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument/8")
 4725     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument/9")
 4726     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument/10")
 4727     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument/11")
 4728     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument/12")
 4729     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument/13")
 4730     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument/14")
 4731     # . epilogue
 4732     89/<- %esp 5/r32/ebp
 4733     5d/pop-to-ebp
 4734     c3/return
 4735 
 4736 test-convert-get-on-function-argument-with-known-type:
 4737     # . prologue
 4738     55/push-ebp
 4739     89/<- %ebp 4/r32/esp
 4740     # setup
 4741     (clear-stream _test-input-stream)
 4742     (clear-stream $_test-input-buffered-file->buffer)
 4743     (clear-stream _test-output-stream)
 4744     (clear-stream $_test-output-buffered-file->buffer)
 4745     #
 4746     (write _test-input-stream "type t {\n")
 4747     (write _test-input-stream "  x: int\n")
 4748     (write _test-input-stream "  y: int\n")
 4749     (write _test-input-stream "}\n")
 4750     (write _test-input-stream "fn foo a: t {\n")
 4751     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 4752     (write _test-input-stream "}\n")
 4753     # convert
 4754     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4755     (flush _test-output-buffered-file)
 4756 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4762     # check output
 4763     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument-with-known-type/0")
 4764     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument-with-known-type/1")
 4765     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument-with-known-type/2")
 4766     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument-with-known-type/3")
 4767     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument-with-known-type/4")
 4768     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument-with-known-type/5")
 4769     # var c
 4770     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument-with-known-type/6")
 4771     # get
 4772     (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")
 4773     # reclaim c
 4774     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument-with-known-type/8")
 4775     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument-with-known-type/9")
 4776     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument-with-known-type/10")
 4777     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument-with-known-type/11")
 4778     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument-with-known-type/12")
 4779     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument-with-known-type/13")
 4780     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument-with-known-type/14")
 4781     # . epilogue
 4782     89/<- %esp 5/r32/ebp
 4783     5d/pop-to-ebp
 4784     c3/return
 4785 
 4786 test-add-with-too-many-inouts:
 4787     # . prologue
 4788     55/push-ebp
 4789     89/<- %ebp 4/r32/esp
 4790     # setup
 4791     (clear-stream _test-input-stream)
 4792     (clear-stream $_test-input-buffered-file->buffer)
 4793     (clear-stream _test-output-stream)
 4794     (clear-stream $_test-output-buffered-file->buffer)
 4795     (clear-stream _test-error-stream)
 4796     (clear-stream $_test-error-buffered-file->buffer)
 4797     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 4798     68/push 0/imm32
 4799     68/push 0/imm32
 4800     89/<- %edx 4/r32/esp
 4801     (tailor-exit-descriptor %edx 0x10)
 4802     #
 4803     (write _test-input-stream "fn foo {\n")
 4804     (write _test-input-stream "  var a: int\n")
 4805     (write _test-input-stream "  var b/ecx: int <- add a, 0\n")
 4806     (write _test-input-stream "}\n")
 4807     # convert
 4808     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 4809     # registers except esp clobbered at this point
 4810     # restore ed
 4811     89/<- %edx 4/r32/esp
 4812     (flush _test-output-buffered-file)
 4813     (flush _test-error-buffered-file)
 4814 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 4820     # check output
 4821     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-inouts: output should be empty")
 4822     (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")
 4823     # check that stop(1) was called
 4824     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-inouts: exit status")
 4825     # don't restore from ebp
 4826     81 0/subop/add %esp 8/imm32
 4827     # . epilogue
 4828     5d/pop-to-ebp
 4829     c3/return
 4830 
 4831 test-add-with-too-many-inouts-2:
 4832     # . prologue
 4833     55/push-ebp
 4834     89/<- %ebp 4/r32/esp
 4835     # setup
 4836     (clear-stream _test-input-stream)
 4837     (clear-stream $_test-input-buffered-file->buffer)
 4838     (clear-stream _test-output-stream)
 4839     (clear-stream $_test-output-buffered-file->buffer)
 4840     (clear-stream _test-error-stream)
 4841     (clear-stream $_test-error-buffered-file->buffer)
 4842     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 4843     68/push 0/imm32
 4844     68/push 0/imm32
 4845     89/<- %edx 4/r32/esp
 4846     (tailor-exit-descriptor %edx 0x10)
 4847     #
 4848     (write _test-input-stream "fn foo {\n")
 4849     (write _test-input-stream "  var a: int\n")
 4850     (write _test-input-stream "  add-to a, 0, 1\n")
 4851     (write _test-input-stream "}\n")
 4852     # convert
 4853     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 4854     # registers except esp clobbered at this point
 4855     # restore ed
 4856     89/<- %edx 4/r32/esp
 4857     (flush _test-output-buffered-file)
 4858     (flush _test-error-buffered-file)
 4859 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 4865     # check output
 4866     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-inouts-2: output should be empty")
 4867     (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")
 4868     # check that stop(1) was called
 4869     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-inouts-2: exit status")
 4870     # don't restore from ebp
 4871     81 0/subop/add %esp 8/imm32
 4872     # . epilogue
 4873     5d/pop-to-ebp
 4874     c3/return
 4875 
 4876 test-add-with-too-many-outputs:
 4877     # . prologue
 4878     55/push-ebp
 4879     89/<- %ebp 4/r32/esp
 4880     # setup
 4881     (clear-stream _test-input-stream)
 4882     (clear-stream $_test-input-buffered-file->buffer)
 4883     (clear-stream _test-output-stream)
 4884     (clear-stream $_test-output-buffered-file->buffer)
 4885     (clear-stream _test-error-stream)
 4886     (clear-stream $_test-error-buffered-file->buffer)
 4887     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 4888     68/push 0/imm32
 4889     68/push 0/imm32
 4890     89/<- %edx 4/r32/esp
 4891     (tailor-exit-descriptor %edx 0x10)
 4892     #
 4893     (write _test-input-stream "fn foo {\n")
 4894     (write _test-input-stream "  var a/eax: int <- copy 0\n")
 4895     (write _test-input-stream "  var b/ebx: int <- copy 0\n")
 4896     (write _test-input-stream "  var c/ecx: int <- copy 0\n")
 4897     (write _test-input-stream "  c, b <- add a\n")
 4898     (write _test-input-stream "}\n")
 4899     # convert
 4900     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 4901     # registers except esp clobbered at this point
 4902     # restore ed
 4903     89/<- %edx 4/r32/esp
 4904     (flush _test-output-buffered-file)
 4905     (flush _test-error-buffered-file)
 4906 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 4912     # check output
 4913     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-outputs: output should be empty")
 4914     (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")
 4915     # check that stop(1) was called
 4916     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-outputs: exit status")
 4917     # don't restore from ebp
 4918     81 0/subop/add %esp 8/imm32
 4919     # . epilogue
 4920     5d/pop-to-ebp
 4921     c3/return
 4922 
 4923 test-add-with-non-number:
 4924     # . prologue
 4925     55/push-ebp
 4926     89/<- %ebp 4/r32/esp
 4927     # setup
 4928     (clear-stream _test-input-stream)
 4929     (clear-stream $_test-input-buffered-file->buffer)
 4930     (clear-stream _test-output-stream)
 4931     (clear-stream $_test-output-buffered-file->buffer)
 4932     (clear-stream _test-error-stream)
 4933     (clear-stream $_test-error-buffered-file->buffer)
 4934     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 4935     68/push 0/imm32
 4936     68/push 0/imm32
 4937     89/<- %edx 4/r32/esp
 4938     (tailor-exit-descriptor %edx 0x10)
 4939     #
 4940     (write _test-input-stream "fn foo {\n")
 4941     (write _test-input-stream "  var a: int\n")
 4942     (write _test-input-stream "  var b/ecx: (addr int) <- add a\n")
 4943     (write _test-input-stream "}\n")
 4944     # convert
 4945     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 4946     # registers except esp clobbered at this point
 4947     # restore ed
 4948     89/<- %edx 4/r32/esp
 4949     (flush _test-output-buffered-file)
 4950     (flush _test-error-buffered-file)
 4951 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 4957     # check output
 4958     (check-stream-equal _test-output-stream  ""  "F - test-add-with-non-number: output should be empty")
 4959     (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")
 4960     # check that stop(1) was called
 4961     (check-ints-equal *(edx+4) 2 "F - test-add-with-non-number: exit status")
 4962     # don't restore from ebp
 4963     81 0/subop/add %esp 8/imm32
 4964     # . epilogue
 4965     5d/pop-to-ebp
 4966     c3/return
 4967 
 4968 test-add-with-addr-dereferenced:
 4969     # . prologue
 4970     55/push-ebp
 4971     89/<- %ebp 4/r32/esp
 4972     # setup
 4973     (clear-stream _test-input-stream)
 4974     (clear-stream $_test-input-buffered-file->buffer)
 4975     (clear-stream _test-output-stream)
 4976     (clear-stream $_test-output-buffered-file->buffer)
 4977     #
 4978     (write _test-input-stream "fn foo {\n")
 4979     (write _test-input-stream "  var a/eax: (addr int) <- copy 0\n")
 4980     (write _test-input-stream "  add-to *a, 1\n")
 4981     (write _test-input-stream "}\n")
 4982     # convert
 4983     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4984     (flush _test-output-buffered-file)
 4985     # no error
 4986     # . epilogue
 4987     89/<- %esp 5/r32/ebp
 4988     5d/pop-to-ebp
 4989     c3/return
 4990 
 4991 test-get-with-wrong-field:
 4992     # . prologue
 4993     55/push-ebp
 4994     89/<- %ebp 4/r32/esp
 4995     # setup
 4996     (clear-stream _test-input-stream)
 4997     (clear-stream $_test-input-buffered-file->buffer)
 4998     (clear-stream _test-output-stream)
 4999     (clear-stream $_test-output-buffered-file->buffer)
 5000     (clear-stream _test-error-stream)
 5001     (clear-stream $_test-error-buffered-file->buffer)
 5002     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5003     68/push 0/imm32
 5004     68/push 0/imm32
 5005     89/<- %edx 4/r32/esp
 5006     (tailor-exit-descriptor %edx 0x10)
 5007     #
 5008     (write _test-input-stream "fn foo {\n")
 5009     (write _test-input-stream "  var a: t\n")
 5010     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5011     (write _test-input-stream "}\n")
 5012     (write _test-input-stream "type t {\n")
 5013     (write _test-input-stream "  x: int\n")
 5014     (write _test-input-stream "}\n")
 5015     # convert
 5016     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5017     # registers except esp clobbered at this point
 5018     # restore ed
 5019     89/<- %edx 4/r32/esp
 5020     (flush _test-output-buffered-file)
 5021     (flush _test-error-buffered-file)
 5022 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5028     # check output
 5029     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-field: output should be empty")
 5030     (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")
 5031     # check that stop(1) was called
 5032     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-field: exit status")
 5033     # don't restore from ebp
 5034     81 0/subop/add %esp 8/imm32
 5035     # . epilogue
 5036     5d/pop-to-ebp
 5037     c3/return
 5038 
 5039 test-get-with-wrong-base-type:
 5040     # . prologue
 5041     55/push-ebp
 5042     89/<- %ebp 4/r32/esp
 5043     # setup
 5044     (clear-stream _test-input-stream)
 5045     (clear-stream $_test-input-buffered-file->buffer)
 5046     (clear-stream _test-output-stream)
 5047     (clear-stream $_test-output-buffered-file->buffer)
 5048     (clear-stream _test-error-stream)
 5049     (clear-stream $_test-error-buffered-file->buffer)
 5050     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5051     68/push 0/imm32
 5052     68/push 0/imm32
 5053     89/<- %edx 4/r32/esp
 5054     (tailor-exit-descriptor %edx 0x10)
 5055     #
 5056     (write _test-input-stream "fn foo {\n")
 5057     (write _test-input-stream "  var a: int\n")
 5058     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5059     (write _test-input-stream "}\n")
 5060     # convert
 5061     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5062     # registers except esp clobbered at this point
 5063     # restore ed
 5064     89/<- %edx 4/r32/esp
 5065     (flush _test-output-buffered-file)
 5066     (flush _test-error-buffered-file)
 5067 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5073     # check output
 5074     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-base-type: output should be empty")
 5075     (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")
 5076     # check that stop(1) was called
 5077     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-base-type: exit status")
 5078     # don't restore from ebp
 5079     81 0/subop/add %esp 8/imm32
 5080     # . epilogue
 5081     5d/pop-to-ebp
 5082     c3/return
 5083 
 5084 test-get-with-wrong-base-type-2:
 5085     # . prologue
 5086     55/push-ebp
 5087     89/<- %ebp 4/r32/esp
 5088     # setup
 5089     (clear-stream _test-input-stream)
 5090     (clear-stream $_test-input-buffered-file->buffer)
 5091     (clear-stream _test-output-stream)
 5092     (clear-stream $_test-output-buffered-file->buffer)
 5093     (clear-stream _test-error-stream)
 5094     (clear-stream $_test-error-buffered-file->buffer)
 5095     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5096     68/push 0/imm32
 5097     68/push 0/imm32
 5098     89/<- %edx 4/r32/esp
 5099     (tailor-exit-descriptor %edx 0x10)
 5100     #
 5101     (write _test-input-stream "fn foo {\n")
 5102     (write _test-input-stream "  var a: (addr t)\n")
 5103     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5104     (write _test-input-stream "}\n")
 5105     (write _test-input-stream "type t {\n")
 5106     (write _test-input-stream "  x: int\n")
 5107     (write _test-input-stream "}\n")
 5108     # convert
 5109     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5110     # registers except esp clobbered at this point
 5111     # restore ed
 5112     89/<- %edx 4/r32/esp
 5113     (flush _test-output-buffered-file)
 5114     (flush _test-error-buffered-file)
 5115 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5121     # check output
 5122     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-base-type-2: output should be empty")
 5123     (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")
 5124     # check that stop(1) was called
 5125     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-base-type-2: exit status")
 5126     # don't restore from ebp
 5127     81 0/subop/add %esp 8/imm32
 5128     # . epilogue
 5129     5d/pop-to-ebp
 5130     c3/return
 5131 
 5132 test-get-with-wrong-offset-type:
 5133     # . prologue
 5134     55/push-ebp
 5135     89/<- %ebp 4/r32/esp
 5136     # setup
 5137     (clear-stream _test-input-stream)
 5138     (clear-stream $_test-input-buffered-file->buffer)
 5139     (clear-stream _test-output-stream)
 5140     (clear-stream $_test-output-buffered-file->buffer)
 5141     (clear-stream _test-error-stream)
 5142     (clear-stream $_test-error-buffered-file->buffer)
 5143     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5144     68/push 0/imm32
 5145     68/push 0/imm32
 5146     89/<- %edx 4/r32/esp
 5147     (tailor-exit-descriptor %edx 0x10)
 5148     #
 5149     (write _test-input-stream "fn foo {\n")
 5150     (write _test-input-stream "  var a: t\n")
 5151     (write _test-input-stream "  var b: int\n")
 5152     (write _test-input-stream "  var c/ecx: (addr int) <- get a, b\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-offset-type: output should be empty")
 5172     (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")
 5173     # check that stop(1) was called
 5174     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-offset-type: 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-output-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 c: (addr int)\n")
 5201     (write _test-input-stream "  c <- get a, x\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-output-type: output should be empty")
 5221     (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")
 5222     # check that stop(1) was called
 5223     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-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-2:
 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/ecx: int <- get a, x\n")
 5250     (write _test-input-stream "}\n")
 5251     (write _test-input-stream "type t {\n")
 5252     (write _test-input-stream "  x: int\n")
 5253     (write _test-input-stream "}\n")
 5254     # convert
 5255     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5256     # registers except esp clobbered at this point
 5257     # restore ed
 5258     89/<- %edx 4/r32/esp
 5259     (flush _test-output-buffered-file)
 5260     (flush _test-error-buffered-file)
 5261 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5267     # check output
 5268     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-2: output should be empty")
 5269     (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")
 5270     # check that stop(1) was called
 5271     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-2: exit status")
 5272     # don't restore from ebp
 5273     81 0/subop/add %esp 8/imm32
 5274     # . epilogue
 5275     5d/pop-to-ebp
 5276     c3/return
 5277 
 5278 test-get-with-wrong-output-type-3:
 5279     # . prologue
 5280     55/push-ebp
 5281     89/<- %ebp 4/r32/esp
 5282     # setup
 5283     (clear-stream _test-input-stream)
 5284     (clear-stream $_test-input-buffered-file->buffer)
 5285     (clear-stream _test-output-stream)
 5286     (clear-stream $_test-output-buffered-file->buffer)
 5287     (clear-stream _test-error-stream)
 5288     (clear-stream $_test-error-buffered-file->buffer)
 5289     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5290     68/push 0/imm32
 5291     68/push 0/imm32
 5292     89/<- %edx 4/r32/esp
 5293     (tailor-exit-descriptor %edx 0x10)
 5294     #
 5295     (write _test-input-stream "fn foo {\n")
 5296     (write _test-input-stream "  var a: t\n")
 5297     (write _test-input-stream "  var c/ecx: (array int) <- get a, x\n")
 5298     (write _test-input-stream "}\n")
 5299     (write _test-input-stream "type t {\n")
 5300     (write _test-input-stream "  x: int\n")
 5301     (write _test-input-stream "}\n")
 5302     # convert
 5303     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5304     # registers except esp clobbered at this point
 5305     # restore ed
 5306     89/<- %edx 4/r32/esp
 5307     (flush _test-output-buffered-file)
 5308     (flush _test-error-buffered-file)
 5309 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5315     # check output
 5316     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-3: output should be empty")
 5317     (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")
 5318     # check that stop(1) was called
 5319     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-3: exit status")
 5320     # don't restore from ebp
 5321     81 0/subop/add %esp 8/imm32
 5322     # . epilogue
 5323     5d/pop-to-ebp
 5324     c3/return
 5325 
 5326 test-get-with-wrong-output-type-4:
 5327     # . prologue
 5328     55/push-ebp
 5329     89/<- %ebp 4/r32/esp
 5330     # setup
 5331     (clear-stream _test-input-stream)
 5332     (clear-stream $_test-input-buffered-file->buffer)
 5333     (clear-stream _test-output-stream)
 5334     (clear-stream $_test-output-buffered-file->buffer)
 5335     (clear-stream _test-error-stream)
 5336     (clear-stream $_test-error-buffered-file->buffer)
 5337     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5338     68/push 0/imm32
 5339     68/push 0/imm32
 5340     89/<- %edx 4/r32/esp
 5341     (tailor-exit-descriptor %edx 0x10)
 5342     #
 5343     (write _test-input-stream "fn foo {\n")
 5344     (write _test-input-stream "  var a: t\n")
 5345     (write _test-input-stream "  var c/ecx: (addr boolean) <- get a, x\n")
 5346     (write _test-input-stream "}\n")
 5347     (write _test-input-stream "type t {\n")
 5348     (write _test-input-stream "  x: int\n")
 5349     (write _test-input-stream "}\n")
 5350     # convert
 5351     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5352     # registers except esp clobbered at this point
 5353     # restore ed
 5354     89/<- %edx 4/r32/esp
 5355     (flush _test-output-buffered-file)
 5356     (flush _test-error-buffered-file)
 5357 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5363     # check output
 5364     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-4: output should be empty")
 5365     (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")
 5366     # check that stop(1) was called
 5367     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-4: exit status")
 5368     # don't restore from ebp
 5369     81 0/subop/add %esp 8/imm32
 5370     # . epilogue
 5371     5d/pop-to-ebp
 5372     c3/return
 5373 
 5374 test-get-with-wrong-output-type-5:
 5375     # . prologue
 5376     55/push-ebp
 5377     89/<- %ebp 4/r32/esp
 5378     # setup
 5379     (clear-stream _test-input-stream)
 5380     (clear-stream $_test-input-buffered-file->buffer)
 5381     (clear-stream _test-output-stream)
 5382     (clear-stream $_test-output-buffered-file->buffer)
 5383     #
 5384     (write _test-input-stream "fn foo {\n")
 5385     (write _test-input-stream "  var a: t\n")
 5386     (write _test-input-stream "  var c/ecx: (addr handle int) <- get a, x\n")
 5387     (write _test-input-stream "}\n")
 5388     (write _test-input-stream "type t {\n")
 5389     (write _test-input-stream "  x: (handle int)\n")
 5390     (write _test-input-stream "}\n")
 5391     # convert
 5392     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5393     (flush _test-output-buffered-file)
 5394     # no errors
 5395     # . epilogue
 5396     89/<- %esp 5/r32/ebp
 5397     5d/pop-to-ebp
 5398     c3/return
 5399 
 5400 test-get-with-too-few-inouts:
 5401     # . prologue
 5402     55/push-ebp
 5403     89/<- %ebp 4/r32/esp
 5404     # setup
 5405     (clear-stream _test-input-stream)
 5406     (clear-stream $_test-input-buffered-file->buffer)
 5407     (clear-stream _test-output-stream)
 5408     (clear-stream $_test-output-buffered-file->buffer)
 5409     (clear-stream _test-error-stream)
 5410     (clear-stream $_test-error-buffered-file->buffer)
 5411     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5412     68/push 0/imm32
 5413     68/push 0/imm32
 5414     89/<- %edx 4/r32/esp
 5415     (tailor-exit-descriptor %edx 0x10)
 5416     #
 5417     (write _test-input-stream "fn foo {\n")
 5418     (write _test-input-stream "  var a: t\n")
 5419     (write _test-input-stream "  var c/ecx: (addr int) <- get a\n")
 5420     (write _test-input-stream "}\n")
 5421     (write _test-input-stream "type t {\n")
 5422     (write _test-input-stream "  x: int\n")
 5423     (write _test-input-stream "}\n")
 5424     # convert
 5425     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5426     # registers except esp clobbered at this point
 5427     # restore ed
 5428     89/<- %edx 4/r32/esp
 5429     (flush _test-output-buffered-file)
 5430     (flush _test-error-buffered-file)
 5431 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5437     # check output
 5438     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-few-inouts: output should be empty")
 5439     (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")
 5440     # check that stop(1) was called
 5441     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-few-inouts: exit status")
 5442     # don't restore from ebp
 5443     81 0/subop/add %esp 8/imm32
 5444     # . epilogue
 5445     5d/pop-to-ebp
 5446     c3/return
 5447 
 5448 test-get-with-too-many-inouts:
 5449     # . prologue
 5450     55/push-ebp
 5451     89/<- %ebp 4/r32/esp
 5452     # setup
 5453     (clear-stream _test-input-stream)
 5454     (clear-stream $_test-input-buffered-file->buffer)
 5455     (clear-stream _test-output-stream)
 5456     (clear-stream $_test-output-buffered-file->buffer)
 5457     (clear-stream _test-error-stream)
 5458     (clear-stream $_test-error-buffered-file->buffer)
 5459     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5460     68/push 0/imm32
 5461     68/push 0/imm32
 5462     89/<- %edx 4/r32/esp
 5463     (tailor-exit-descriptor %edx 0x10)
 5464     #
 5465     (write _test-input-stream "fn foo {\n")
 5466     (write _test-input-stream "  var a: t\n")
 5467     (write _test-input-stream "  var c/ecx: (addr int) <- get a, x, 0\n")
 5468     (write _test-input-stream "}\n")
 5469     (write _test-input-stream "type t {\n")
 5470     (write _test-input-stream "  x: int\n")
 5471     (write _test-input-stream "}\n")
 5472     # convert
 5473     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5474     # registers except esp clobbered at this point
 5475     # restore ed
 5476     89/<- %edx 4/r32/esp
 5477     (flush _test-output-buffered-file)
 5478     (flush _test-error-buffered-file)
 5479 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5485     # check output
 5486     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-many-inouts: output should be empty")
 5487     (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")
 5488     # check that stop(1) was called
 5489     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-many-inouts: exit status")
 5490     # don't restore from ebp
 5491     81 0/subop/add %esp 8/imm32
 5492     # . epilogue
 5493     5d/pop-to-ebp
 5494     c3/return
 5495 
 5496 test-get-with-no-output:
 5497     # . prologue
 5498     55/push-ebp
 5499     89/<- %ebp 4/r32/esp
 5500     # setup
 5501     (clear-stream _test-input-stream)
 5502     (clear-stream $_test-input-buffered-file->buffer)
 5503     (clear-stream _test-output-stream)
 5504     (clear-stream $_test-output-buffered-file->buffer)
 5505     (clear-stream _test-error-stream)
 5506     (clear-stream $_test-error-buffered-file->buffer)
 5507     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5508     68/push 0/imm32
 5509     68/push 0/imm32
 5510     89/<- %edx 4/r32/esp
 5511     (tailor-exit-descriptor %edx 0x10)
 5512     #
 5513     (write _test-input-stream "fn foo {\n")
 5514     (write _test-input-stream "  var a: t\n")
 5515     (write _test-input-stream "  get a, x\n")
 5516     (write _test-input-stream "}\n")
 5517     (write _test-input-stream "type t {\n")
 5518     (write _test-input-stream "  x: int\n")
 5519     (write _test-input-stream "}\n")
 5520     # convert
 5521     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5522     # registers except esp clobbered at this point
 5523     # restore ed
 5524     89/<- %edx 4/r32/esp
 5525     (flush _test-output-buffered-file)
 5526     (flush _test-error-buffered-file)
 5527 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5533     # check output
 5534     (check-stream-equal _test-output-stream  ""  "F - test-get-with-no-output: output should be empty")
 5535     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: must have an output"  "F - test-get-with-no-output: error message")
 5536     # check that stop(1) was called
 5537     (check-ints-equal *(edx+4) 2 "F - test-get-with-no-output: exit status")
 5538     # don't restore from ebp
 5539     81 0/subop/add %esp 8/imm32
 5540     # . epilogue
 5541     5d/pop-to-ebp
 5542     c3/return
 5543 
 5544 test-get-with-too-many-outputs:
 5545     # . prologue
 5546     55/push-ebp
 5547     89/<- %ebp 4/r32/esp
 5548     # setup
 5549     (clear-stream _test-input-stream)
 5550     (clear-stream $_test-input-buffered-file->buffer)
 5551     (clear-stream _test-output-stream)
 5552     (clear-stream $_test-output-buffered-file->buffer)
 5553     (clear-stream _test-error-stream)
 5554     (clear-stream $_test-error-buffered-file->buffer)
 5555     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5556     68/push 0/imm32
 5557     68/push 0/imm32
 5558     89/<- %edx 4/r32/esp
 5559     (tailor-exit-descriptor %edx 0x10)
 5560     #
 5561     (write _test-input-stream "fn foo {\n")
 5562     (write _test-input-stream "  var a: t\n")
 5563     (write _test-input-stream "  var b: int\n")
 5564     (write _test-input-stream "  var c/eax: (addr int) <- copy 0\n")
 5565     (write _test-input-stream "  c, b <- get a, x\n")
 5566     (write _test-input-stream "}\n")
 5567     (write _test-input-stream "type t {\n")
 5568     (write _test-input-stream "  x: int\n")
 5569     (write _test-input-stream "}\n")
 5570     # convert
 5571     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5572     # registers except esp clobbered at this point
 5573     # restore ed
 5574     89/<- %edx 4/r32/esp
 5575     (flush _test-output-buffered-file)
 5576     (flush _test-error-buffered-file)
 5577 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5583     # check output
 5584     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-many-outputs: output should be empty")
 5585     (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")
 5586     # check that stop(1) was called
 5587     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-many-outputs: exit status")
 5588     # don't restore from ebp
 5589     81 0/subop/add %esp 8/imm32
 5590     # . epilogue
 5591     5d/pop-to-ebp
 5592     c3/return
 5593 
 5594 test-convert-array-of-user-defined-types:
 5595     # . prologue
 5596     55/push-ebp
 5597     89/<- %ebp 4/r32/esp
 5598     # setup
 5599     (clear-stream _test-input-stream)
 5600     (clear-stream $_test-input-buffered-file->buffer)
 5601     (clear-stream _test-output-stream)
 5602     (clear-stream $_test-output-buffered-file->buffer)
 5603     #
 5604     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
 5605     (write _test-input-stream "  x: int\n")
 5606     (write _test-input-stream "  y: int\n")
 5607     (write _test-input-stream "}\n")
 5608     (write _test-input-stream "fn foo {\n")
 5609     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 5610     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 5611     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 5612     (write _test-input-stream "}\n")
 5613     # convert
 5614     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5615     (flush _test-output-buffered-file)
 5616 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5622     # check output
 5623     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-array-of-user-defined-types/0")
 5624     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-array-of-user-defined-types/1")
 5625     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-array-of-user-defined-types/2")
 5626     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-array-of-user-defined-types/3")
 5627     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-array-of-user-defined-types/4")
 5628     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-array-of-user-defined-types/5")
 5629     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-array-of-user-defined-types/6")
 5630     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-array-of-user-defined-types/7")
 5631     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-array-of-user-defined-types/8")
 5632     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-array-of-user-defined-types/9")
 5633     (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")
 5634     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-array-of-user-defined-types/13")
 5635     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-array-of-user-defined-types/14")
 5636     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-array-of-user-defined-types/15")
 5637     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-array-of-user-defined-types/16")
 5638     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-array-of-user-defined-types/17")
 5639     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-array-of-user-defined-types/18")
 5640     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-array-of-user-defined-types/19")
 5641     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-array-of-user-defined-types/20")
 5642     # . epilogue
 5643     89/<- %esp 5/r32/ebp
 5644     5d/pop-to-ebp
 5645     c3/return
 5646 
 5647 test-convert-length-of-array-of-user-defined-types-to-eax:
 5648     # . prologue
 5649     55/push-ebp
 5650     89/<- %ebp 4/r32/esp
 5651     # setup
 5652     (clear-stream _test-input-stream)
 5653     (clear-stream $_test-input-buffered-file->buffer)
 5654     (clear-stream _test-output-stream)
 5655     (clear-stream $_test-output-buffered-file->buffer)
 5656     #
 5657     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 5658     (write _test-input-stream "  x: int\n")
 5659     (write _test-input-stream "  y: int\n")
 5660     (write _test-input-stream "  z: int\n")
 5661     (write _test-input-stream "}\n")
 5662     (write _test-input-stream "fn foo {\n")
 5663     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 5664     (write _test-input-stream "  var x/eax: (addr t) <- length arr\n")
 5665     (write _test-input-stream "}\n")
 5666     # convert
 5667     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5668     (flush _test-output-buffered-file)
 5669 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5675     # check output
 5676     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-eax/0")
 5677     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/1")
 5678     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-eax/2")
 5679     (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")
 5680     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/4")
 5681     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-eax/5")
 5682     # var arr
 5683     (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")
 5684     (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")
 5685     # length instruction
 5686     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/8")
 5687     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/9")
 5688     (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")
 5689     (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")
 5690     (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")
 5691     (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")
 5692     (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")
 5693     (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")
 5694     # reclaim arr
 5695     (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")
 5696     #
 5697     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/17")
 5698     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/18")
 5699     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/19")
 5700     (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")
 5701     (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")
 5702     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-eax/22")
 5703     # . epilogue
 5704     89/<- %esp 5/r32/ebp
 5705     5d/pop-to-ebp
 5706     c3/return
 5707 
 5708 test-convert-length-of-array-of-user-defined-types-to-ecx:
 5709     # . prologue
 5710     55/push-ebp
 5711     89/<- %ebp 4/r32/esp
 5712     # setup
 5713     (clear-stream _test-input-stream)
 5714     (clear-stream $_test-input-buffered-file->buffer)
 5715     (clear-stream _test-output-stream)
 5716     (clear-stream $_test-output-buffered-file->buffer)
 5717     #
 5718     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 5719     (write _test-input-stream "  x: int\n")
 5720     (write _test-input-stream "  y: int\n")
 5721     (write _test-input-stream "  z: int\n")
 5722     (write _test-input-stream "}\n")
 5723     (write _test-input-stream "fn foo {\n")
 5724     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 5725     (write _test-input-stream "  var x/ecx: (addr t) <- length arr\n")
 5726     (write _test-input-stream "}\n")
 5727     # convert
 5728     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5729     (flush _test-output-buffered-file)
 5730 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5736     # check output
 5737     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-ecx/0")
 5738     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/1")
 5739     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-ecx/2")
 5740     (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")
 5741     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/4")
 5742     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-ecx/5")
 5743     # var a
 5744     (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")
 5745     (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")
 5746     # var x
 5747     (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")
 5748     # length instruction
 5749     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/9")
 5750     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/10")
 5751     (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")
 5752     (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")
 5753     (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")
 5754     (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")
 5755     (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")
 5756     (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")
 5757     (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")
 5758     # reclaim x
 5759     (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")
 5760     # reclaim a
 5761     (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")
 5762     #
 5763     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/20")
 5764     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/21")
 5765     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/22")
 5766     (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")
 5767     (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")
 5768     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-ecx/25")
 5769     # . epilogue
 5770     89/<- %esp 5/r32/ebp
 5771     5d/pop-to-ebp
 5772     c3/return
 5773 
 5774 test-convert-length-of-array-of-user-defined-types-to-edx:
 5775     # . prologue
 5776     55/push-ebp
 5777     89/<- %ebp 4/r32/esp
 5778     # setup
 5779     (clear-stream _test-input-stream)
 5780     (clear-stream $_test-input-buffered-file->buffer)
 5781     (clear-stream _test-output-stream)
 5782     (clear-stream $_test-output-buffered-file->buffer)
 5783     #
 5784     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 5785     (write _test-input-stream "  x: int\n")
 5786     (write _test-input-stream "  y: int\n")
 5787     (write _test-input-stream "  z: int\n")
 5788     (write _test-input-stream "}\n")
 5789     (write _test-input-stream "fn foo {\n")
 5790     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 5791     (write _test-input-stream "  var x/edx: (addr t) <- length arr\n")
 5792     (write _test-input-stream "}\n")
 5793     # convert
 5794     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5795     (flush _test-output-buffered-file)
 5796 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5802     # check output
 5803     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-edx/0")
 5804     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/1")
 5805     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-edx/2")
 5806     (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")
 5807     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/4")
 5808     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-edx/5")
 5809     # var a
 5810     (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")
 5811     (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")
 5812     # var x
 5813     (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")
 5814     # length instruction
 5815     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/9")
 5816     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/10")
 5817     (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")
 5818     (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")
 5819     (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")
 5820     (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")
 5821     (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")
 5822     (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")
 5823     (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")
 5824     # reclaim x
 5825     (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")
 5826     # reclaim a
 5827     (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")
 5828     #
 5829     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/20")
 5830     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/21")
 5831     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/22")
 5832     (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")
 5833     (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")
 5834     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-edx/25")
 5835     # . epilogue
 5836     89/<- %esp 5/r32/ebp
 5837     5d/pop-to-ebp
 5838     c3/return
 5839 
 5840 test-convert-length-of-array-of-user-defined-types:
 5841     # . prologue
 5842     55/push-ebp
 5843     89/<- %ebp 4/r32/esp
 5844     # setup
 5845     (clear-stream _test-input-stream)
 5846     (clear-stream $_test-input-buffered-file->buffer)
 5847     (clear-stream _test-output-stream)
 5848     (clear-stream $_test-output-buffered-file->buffer)
 5849     #
 5850     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
 5851     (write _test-input-stream "  x: int\n")
 5852     (write _test-input-stream "  y: int\n")
 5853     (write _test-input-stream "  z: int\n")
 5854     (write _test-input-stream "}\n")
 5855     (write _test-input-stream "fn foo {\n")
 5856     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 5857     (write _test-input-stream "  var x/ebx: (addr t) <- length arr\n")
 5858     (write _test-input-stream "}\n")
 5859     # convert
 5860     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5861     (flush _test-output-buffered-file)
 5862 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5868     # check output
 5869     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types/0")
 5870     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types/1")
 5871     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types/2")
 5872     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-user-defined-types/3")
 5873     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types/4")
 5874     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types/5")
 5875     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-user-defined-types/6")
 5876     (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")
 5877     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ebx"  "F - test-convert-length-of-array-of-user-defined-types/8")
 5878     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types/9")
 5879     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types/10")
 5880     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types/11")
 5881     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-user-defined-types/12")
 5882     (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")
 5883     (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")
 5884     (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")
 5885     (check-next-stream-line-equal _test-output-stream "    89/<- %ebx 0/r32/eax"  "F - test-convert-length-of-array-of-user-defined-types/16")
 5886     (check-next-stream-line-equal _test-output-stream "    5a/pop-to-edx"       "F - test-convert-length-of-array-of-user-defined-types/17")
 5887     (check-next-stream-line-equal _test-output-stream "    59/pop-to-ecx"       "F - test-convert-length-of-array-of-user-defined-types/18")
 5888     (check-next-stream-line-equal _test-output-stream "    58/pop-to-eax"       "F - test-convert-length-of-array-of-user-defined-types/19")
 5889     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ebx"  "F - test-convert-length-of-array-of-user-defined-types/20")
 5890     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-user-defined-types/21")
 5891     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types/22")
 5892     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types/23")
 5893     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types/24")
 5894     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-user-defined-types/25")
 5895     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-user-defined-types/26")
 5896     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types/27")
 5897     # . epilogue
 5898     89/<- %esp 5/r32/ebp
 5899     5d/pop-to-ebp
 5900     c3/return
 5901 
 5902 #######################################################
 5903 # Parsing
 5904 #######################################################
 5905 
 5906 == data
 5907 
 5908 # Global state added to each var record when parsing a function
 5909 Next-block-index:  # (addr int)
 5910     1/imm32
 5911 
 5912 Curr-block-depth:  # (addr int)
 5913     1/imm32
 5914 
 5915 == code
 5916 
 5917 parse-mu:  # in: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
 5918     # pseudocode
 5919     #   var curr-function: (addr handle function) = Program->functions
 5920     #   var curr-type: (addr handle typeinfo) = Program->types
 5921     #   var line: (stream byte 512)
 5922     #   var word-slice: slice
 5923     #   while true                                  # line loop
 5924     #     clear-stream(line)
 5925     #     read-line-buffered(in, line)
 5926     #     if (line->write == 0) break               # end of file
 5927     #     word-slice = next-mu-token(line)
 5928     #     if slice-empty?(word-slice)               # end of line
 5929     #       continue
 5930     #     else if slice-starts-with?(word-slice, "#")  # comment
 5931     #       continue                                # end of line
 5932     #     else if slice-equal?(word-slice, "fn")
 5933     #       var new-function: (handle function) = allocate(function)
 5934     #       var vars: (stack live-var 256)
 5935     #       populate-mu-function-header(line, new-function, vars)
 5936     #       populate-mu-function-body(in, new-function, vars)
 5937     #       assert(vars->top == 0)
 5938     #       *curr-function = new-function
 5939     #       curr-function = &new-function->next
 5940     #     else if slice-equal?(word-slice, "type")
 5941     #       word-slice = next-mu-token(line)
 5942     #       type-id = pos-or-insert-slice(Type-id, word-slice)
 5943     #       var new-type: (handle typeinfo) = find-or-create-typeinfo(type-id)
 5944     #       assert(next-word(line) == "{")
 5945     #       populate-mu-type(in, new-type)
 5946     #     else
 5947     #       abort()
 5948     #
 5949     # . prologue
 5950     55/push-ebp
 5951     89/<- %ebp 4/r32/esp
 5952     # . save registers
 5953     50/push-eax
 5954     51/push-ecx
 5955     52/push-edx
 5956     53/push-ebx
 5957     56/push-esi
 5958     57/push-edi
 5959     # var line/ecx: (stream byte 512)
 5960     81 5/subop/subtract %esp 0x200/imm32
 5961     68/push 0x200/imm32/size
 5962     68/push 0/imm32/read
 5963     68/push 0/imm32/write
 5964     89/<- %ecx 4/r32/esp
 5965     # var word-slice/edx: slice
 5966     68/push 0/imm32/end
 5967     68/push 0/imm32/start
 5968     89/<- %edx 4/r32/esp
 5969     # var curr-function/edi: (addr handle function)
 5970     bf/copy-to-edi _Program-functions/imm32
 5971     # var vars/ebx: (stack live-var 256)
 5972     81 5/subop/subtract %esp 0xc00/imm32
 5973     68/push 0xc00/imm32/size
 5974     68/push 0/imm32/top
 5975     89/<- %ebx 4/r32/esp
 5976     {
 5977 $parse-mu:line-loop:
 5978       (clear-stream %ecx)
 5979       (read-line-buffered *(ebp+8) %ecx)
 5980       # if (line->write == 0) break
 5981       81 7/subop/compare *ecx 0/imm32
 5982       0f 84/jump-if-= break/disp32
 5983 +--  6 lines: #?       # dump line ------------------------------------------------------------------------------------------------------------------------------------------------------
 5989       (next-mu-token %ecx %edx)
 5990       # if slice-empty?(word-slice) continue
 5991       (slice-empty? %edx)  # => eax
 5992       3d/compare-eax-and 0/imm32/false
 5993       0f 85/jump-if-!= loop/disp32
 5994       # if (*word-slice->start == "#") continue
 5995       # . eax = *word-slice->start
 5996       8b/-> *edx 0/r32/eax
 5997       8a/copy-byte *eax 0/r32/AL
 5998       81 4/subop/and %eax 0xff/imm32
 5999       # . if (eax == '#') continue
 6000       3d/compare-eax-and 0x23/imm32/hash
 6001       0f 84/jump-if-= loop/disp32
 6002       # if (slice-equal?(word-slice, "fn")) parse a function
 6003       {
 6004 $parse-mu:fn:
 6005         (slice-equal? %edx "fn")  # => eax
 6006         3d/compare-eax-and 0/imm32/false
 6007         0f 84/jump-if-= break/disp32
 6008         # var new-function/esi: (handle function)
 6009         68/push 0/imm32
 6010         68/push 0/imm32
 6011         89/<- %esi 4/r32/esp
 6012         # populate-mu-function(line, in, vars, new-function)
 6013         (allocate Heap *Function-size %esi)
 6014         # var new-function-addr/eax: (addr function)
 6015         (lookup *esi *(esi+4))  # => eax
 6016         (clear-stack %ebx)
 6017         (populate-mu-function-header %ecx %eax %ebx *(ebp+0xc) *(ebp+0x10))
 6018         (populate-mu-function-body *(ebp+8) %eax %ebx *(ebp+0xc) *(ebp+0x10))
 6019         # *curr-function = new-function
 6020         8b/-> *esi 0/r32/eax
 6021         89/<- *edi 0/r32/eax
 6022         8b/-> *(esi+4) 0/r32/eax
 6023         89/<- *(edi+4) 0/r32/eax
 6024         # curr-function = &new-function->next
 6025         # . var tmp/eax: (addr function) = lookup(new-function)
 6026         (lookup *esi *(esi+4))  # => eax
 6027         # . curr-function = &tmp->next
 6028         8d/copy-address *(eax+0x20) 7/r32/edi  # Function-next
 6029         # reclaim new-function
 6030         81 0/subop/add %esp 8/imm32
 6031         #
 6032         e9/jump $parse-mu:line-loop/disp32
 6033       }
 6034       # if (slice-equal?(word-slice, "type")) parse a type (struct/record) definition
 6035       {
 6036 $parse-mu:type:
 6037         (slice-equal? %edx "type")  # => eax
 6038         3d/compare-eax-and 0/imm32
 6039         0f 84/jump-if-= break/disp32
 6040         (next-mu-token %ecx %edx)
 6041         # var type-id/eax: int
 6042         (pos-or-insert-slice Type-id %edx)  # => eax
 6043         # spill
 6044         51/push-ecx
 6045         # var new-type/ecx: (handle typeinfo)
 6046         68/push 0/imm32
 6047         68/push 0/imm32
 6048         89/<- %ecx 4/r32/esp
 6049         (find-or-create-typeinfo %eax %ecx)
 6050         #
 6051         (lookup *ecx *(ecx+4))  # => eax
 6052         # TODO: ensure that 'line' has nothing else but '{'
 6053 #? (dump-typeinfos "=== aaa\n")
 6054         (populate-mu-type *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))  # => eax
 6055 #? (dump-typeinfos "=== zzz\n")
 6056         # reclaim new-type
 6057         81 0/subop/add %esp 8/imm32
 6058         # restore
 6059         59/pop-to-ecx
 6060         e9/jump $parse-mu:line-loop/disp32
 6061       }
 6062       # otherwise abort
 6063       e9/jump $parse-mu:error1/disp32
 6064     } # end line loop
 6065 $parse-mu:end:
 6066     # . reclaim locals
 6067     81 0/subop/add %esp 0xe1c/imm32
 6068     # . restore registers
 6069     5f/pop-to-edi
 6070     5e/pop-to-esi
 6071     5b/pop-to-ebx
 6072     5a/pop-to-edx
 6073     59/pop-to-ecx
 6074     58/pop-to-eax
 6075     # . epilogue
 6076     89/<- %esp 5/r32/ebp
 6077     5d/pop-to-ebp
 6078     c3/return
 6079 
 6080 $parse-mu:error1:
 6081     # error("unexpected top-level command: " word-slice "\n")
 6082     (write-buffered *(ebp+0xc) "unexpected top-level command: ")
 6083     (write-slice-buffered *(ebp+0xc) %edx)
 6084     (write-buffered *(ebp+0xc) "\n")
 6085     (flush *(ebp+0xc))
 6086     (stop *(ebp+0x10) 1)
 6087     # never gets here
 6088 
 6089 $parse-mu:error2:
 6090     # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n")
 6091     (write-int32-hex-buffered *(ebp+0xc) *ebx)
 6092     (write-buffered *(ebp+0xc) " vars not reclaimed after fn '")
 6093     (write-slice-buffered *(ebp+0xc) *eax)  # Function-name
 6094     (write-buffered *(ebp+0xc) "'\n")
 6095     (flush *(ebp+0xc))
 6096     (stop *(ebp+0x10) 1)
 6097     # never gets here
 6098 
 6099 # scenarios considered:
 6100 # ✗ fn foo  # no block
 6101 # ✓ fn foo {
 6102 # ✗ fn foo { {
 6103 # ✗ fn foo { }
 6104 # ✗ fn foo { } {
 6105 # ✗ fn foo x {
 6106 # ✗ fn foo x: {
 6107 # ✓ fn foo x: int {
 6108 # ✓ fn foo x: int {
 6109 # ✓ fn foo x: int -> y/eax: int {
 6110 # TODO:
 6111 #   disallow outputs of type `(... addr ...)`
 6112 #   disallow inputs of type `(... addr ... addr ...)`
 6113 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)
 6114     # pseudocode:
 6115     #   var name: slice
 6116     #   next-mu-token(first-line, name)
 6117     #   assert(name not in '{' '}' '->')
 6118     #   out->name = slice-to-string(name)
 6119     #   ## inouts
 6120     #   while true
 6121     #     ## name
 6122     #     name = next-mu-token(first-line)
 6123     #     if (name == '{') goto done
 6124     #     if (name == '->') break
 6125     #     assert(name != '}')
 6126     #     var v: (handle var) = parse-var-with-type(name, first-line)
 6127     #     assert(v->register == null)
 6128     #     # v->block-depth is implicitly 0
 6129     #     out->inouts = append(v, out->inouts)
 6130     #     push(vars, {v, false})
 6131     #   ## outputs
 6132     #   while true
 6133     #     ## name
 6134     #     name = next-mu-token(first-line)
 6135     #     assert(name not in '{' '}' '->')
 6136     #     var v: (handle var) = parse-var-with-type(name, first-line)
 6137     #     assert(v->register != null)
 6138     #     out->outputs = append(v, out->outputs)
 6139     #   done:
 6140     #
 6141     # . prologue
 6142     55/push-ebp
 6143     89/<- %ebp 4/r32/esp
 6144     # . save registers
 6145     50/push-eax
 6146     51/push-ecx
 6147     52/push-edx
 6148     53/push-ebx
 6149     57/push-edi
 6150     # edi = out
 6151     8b/-> *(ebp+0xc) 7/r32/edi
 6152     # var word-slice/ecx: slice
 6153     68/push 0/imm32/end
 6154     68/push 0/imm32/start
 6155     89/<- %ecx 4/r32/esp
 6156     # var v/ebx: (handle var)
 6157     68/push 0/imm32
 6158     68/push 0/imm32
 6159     89/<- %ebx 4/r32/esp
 6160     # read function name
 6161     (next-mu-token *(ebp+8) %ecx)
 6162     # error checking
 6163     # TODO: error if name starts with 'break' or 'loop'
 6164     # if (word-slice == '{') abort
 6165     (slice-equal? %ecx "{")   # => eax
 6166     3d/compare-eax-and 0/imm32/false
 6167     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6168     # if (word-slice == '->') abort
 6169     (slice-equal? %ecx "->")   # => eax
 6170     3d/compare-eax-and 0/imm32/false
 6171     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6172     # if (word-slice == '}') abort
 6173     (slice-equal? %ecx "}")   # => eax
 6174     3d/compare-eax-and 0/imm32/false
 6175     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6176     # save function name
 6177     (slice-to-string Heap %ecx %edi)  # Function-name
 6178     # save function inouts
 6179     {
 6180 $populate-mu-function-header:check-for-inout:
 6181       (next-mu-token *(ebp+8) %ecx)
 6182       # if (word-slice == '{') goto done
 6183       (slice-equal? %ecx "{")   # => eax
 6184       3d/compare-eax-and 0/imm32/false
 6185       0f 85/jump-if-!= $populate-mu-function-header:done/disp32
 6186       # if (word-slice == '->') break
 6187       (slice-equal? %ecx "->")   # => eax
 6188       3d/compare-eax-and 0/imm32/false
 6189       0f 85/jump-if-!= break/disp32
 6190       # if (word-slice == '}') abort
 6191       (slice-equal? %ecx "}")   # => eax
 6192       3d/compare-eax-and 0/imm32/false
 6193       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6194       # v = parse-var-with-type(word-slice, first-line)
 6195       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x14) *(ebp+0x18))
 6196       # assert(v->register == null)
 6197       # . eax: (addr var) = lookup(v)
 6198       (lookup *ebx *(ebx+4))  # => eax
 6199       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 6200       0f 85/jump-if-!= $populate-mu-function-header:error2/disp32
 6201       # v->block-depth is implicitly 0
 6202       #
 6203       # out->inouts = append(v, out->inouts)
 6204       8d/copy-address *(edi+8) 0/r32/eax  # Function-inouts
 6205       (append-list Heap  *ebx *(ebx+4)  *(edi+8) *(edi+0xc)  %eax)  # Function-inouts, Function-inouts
 6206       # push(vars, {v, false})
 6207       (push *(ebp+0x10) *ebx)
 6208       (push *(ebp+0x10) *(ebx+4))
 6209       (push *(ebp+0x10) 0)  # false
 6210       #
 6211       e9/jump loop/disp32
 6212     }
 6213     # save function outputs
 6214     {
 6215 $populate-mu-function-header:check-for-out:
 6216       (next-mu-token *(ebp+8) %ecx)
 6217       # if (word-slice == '{') break
 6218       (slice-equal? %ecx "{")   # => eax
 6219       3d/compare-eax-and 0/imm32/false
 6220       0f 85/jump-if-!= break/disp32
 6221       # if (word-slice == '->') abort
 6222       (slice-equal? %ecx "->")   # => eax
 6223       3d/compare-eax-and 0/imm32/false
 6224       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6225       # if (word-slice == '}') abort
 6226       (slice-equal? %ecx "}")   # => eax
 6227       3d/compare-eax-and 0/imm32/false
 6228       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6229       # v = parse-var-with-type(word-slice, first-line)
 6230       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x14) *(ebp+0x18))
 6231       # assert(var->register != null)
 6232       # . eax: (addr var) = lookup(v)
 6233       (lookup *ebx *(ebx+4))  # => eax
 6234       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 6235       0f 84/jump-if-= $populate-mu-function-header:error3/disp32
 6236       # out->outputs = append(v, out->outputs)
 6237       8d/copy-address *(edi+0x10) 0/r32/eax  # Function-outputs
 6238       (append-list Heap  *ebx *(ebx+4)  *(edi+0x10) *(edi+0x14)  %eax)  # Function-outputs, Function-outputs
 6239       #
 6240       e9/jump loop/disp32
 6241     }
 6242 $populate-mu-function-header:done:
 6243     (check-no-tokens-left *(ebp+8))
 6244 $populate-mu-function-header:end:
 6245     # . reclaim locals
 6246     81 0/subop/add %esp 0x10/imm32
 6247     # . restore registers
 6248     5f/pop-to-edi
 6249     5b/pop-to-ebx
 6250     5a/pop-to-edx
 6251     59/pop-to-ecx
 6252     58/pop-to-eax
 6253     # . epilogue
 6254     89/<- %esp 5/r32/ebp
 6255     5d/pop-to-ebp
 6256     c3/return
 6257 
 6258 $populate-mu-function-header:error1:
 6259     # error("function header not in form 'fn <name> {'")
 6260     (write-buffered *(ebp+0x14) "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '")
 6261     (flush *(ebp+0x14))
 6262     (rewind-stream *(ebp+8))
 6263     (write-stream-data *(ebp+0x14) *(ebp+8))
 6264     (write-buffered *(ebp+0x14) "'\n")
 6265     (flush *(ebp+0x14))
 6266     (stop *(ebp+0x18) 1)
 6267     # never gets here
 6268 
 6269 $populate-mu-function-header:error2:
 6270     # error("function inout '" var "' cannot be in a register")
 6271     (write-buffered *(ebp+0x14) "function inout '")
 6272     (write-buffered *(ebp+0x14) *ebx)  # Var-name
 6273     (write-buffered *(ebp+0x14) "' cannot be in a register")
 6274     (flush *(ebp+0x14))
 6275     (stop *(ebp+0x18) 1)
 6276     # never gets here
 6277 
 6278 $populate-mu-function-header:error3:
 6279     # error("function output '" var "' must be in a register")
 6280     (write-buffered *(ebp+0x14) "function output '")
 6281     (lookup *ebx *(ebx+4))  # => eax
 6282     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 6283     (write-buffered *(ebp+0x14) %eax)
 6284     (write-buffered *(ebp+0x14) "' must be in a register, in instruction '")
 6285     (rewind-stream *(ebp+8))
 6286     (write-stream-data *(ebp+0x14) *(ebp+8))
 6287     (write-buffered *(ebp+0x14) "'\n")
 6288     (flush *(ebp+0x14))
 6289     (stop *(ebp+0x18) 1)
 6290     # never gets here
 6291 
 6292 test-function-header-with-arg:
 6293     # . prologue
 6294     55/push-ebp
 6295     89/<- %ebp 4/r32/esp
 6296     # setup
 6297     (clear-stream _test-input-stream)
 6298     (write _test-input-stream "foo n: int {\n")
 6299     # var result/ecx: function
 6300     2b/subtract *Function-size 4/r32/esp
 6301     89/<- %ecx 4/r32/esp
 6302     (zero-out %ecx *Function-size)
 6303     # var vars/ebx: (stack live-var 16)
 6304     81 5/subop/subtract %esp 0xc0/imm32
 6305     68/push 0xc0/imm32/size
 6306     68/push 0/imm32/top
 6307     89/<- %ebx 4/r32/esp
 6308     # convert
 6309     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 6310     # check result->name
 6311     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 6312     (check-strings-equal %eax "foo" "F - test-function-header-with-arg/name")
 6313     # var v/edx: (addr var) = result->inouts->value
 6314     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 6315     (lookup *eax *(eax+4))  # List-value List-value => eax
 6316     89/<- %edx 0/r32/eax
 6317     # check v->name
 6318     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 6319     (check-strings-equal %eax "n" "F - test-function-header-with-arg/inout:0")
 6320     # check v->type
 6321     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 6322     (check-ints-equal *eax 1 "F - test-function-header-with-arg/inout:0/type:0")  # Tree-is-atom
 6323     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-arg/inout:0/type:1")  # Tree-value
 6324     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-arg/inout:0/type:2")  # Tree-right
 6325     # . epilogue
 6326     89/<- %esp 5/r32/ebp
 6327     5d/pop-to-ebp
 6328     c3/return
 6329 
 6330 test-function-header-with-multiple-args:
 6331     # . prologue
 6332     55/push-ebp
 6333     89/<- %ebp 4/r32/esp
 6334     # setup
 6335     (clear-stream _test-input-stream)
 6336     (write _test-input-stream "foo a: int, b: int c: int {\n")
 6337     # result/ecx: function
 6338     2b/subtract *Function-size 4/r32/esp
 6339     89/<- %ecx 4/r32/esp
 6340     (zero-out %ecx *Function-size)
 6341     # var vars/ebx: (stack live-var 16)
 6342     81 5/subop/subtract %esp 0xc0/imm32
 6343     68/push 0xc0/imm32/size
 6344     68/push 0/imm32/top
 6345     89/<- %ebx 4/r32/esp
 6346     # convert
 6347     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 6348     # check result->name
 6349     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 6350     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args/name")
 6351     # var inouts/edx: (addr list var) = lookup(result->inouts)
 6352     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 6353     89/<- %edx 0/r32/eax
 6354 $test-function-header-with-multiple-args:inout0:
 6355     # var v/ebx: (addr var) = lookup(inouts->value)
 6356     (lookup *edx *(edx+4))  # List-value List-value => eax
 6357     89/<- %ebx 0/r32/eax
 6358     # check v->name
 6359     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 6360     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args/inout:0")  # Var-name
 6361     # check v->type
 6362     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 6363     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:0/type:0")  # Tree-is-atom
 6364     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:0/type:1")  # Tree-value
 6365     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:0/type:2")  # Tree-right
 6366 $test-function-header-with-multiple-args:inout1:
 6367     # inouts = lookup(inouts->next)
 6368     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 6369     89/<- %edx 0/r32/eax
 6370     # v = lookup(inouts->value)
 6371     (lookup *edx *(edx+4))  # List-value List-value => eax
 6372     89/<- %ebx 0/r32/eax
 6373     # check v->name
 6374     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 6375     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args/inout:1")  # Var-name
 6376     # check v->type
 6377     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 6378     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:1/type:0")  # Tree-is-atom
 6379     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:1/type:1")  # Tree-value
 6380     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:1/type:2")  # Tree-right
 6381 $test-function-header-with-multiple-args:inout2:
 6382     # inouts = lookup(inouts->next)
 6383     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 6384     89/<- %edx 0/r32/eax
 6385     # v = lookup(inouts->value)
 6386     (lookup *edx *(edx+4))  # List-value List-value => eax
 6387     89/<- %ebx 0/r32/eax
 6388     # check v->name
 6389     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 6390     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args/inout:2")  # Var-name
 6391     # check v->type
 6392     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 6393     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:2/type:0")  # Tree-is-atom
 6394     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:2/type:1")  # Tree-value
 6395     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:2/type:2")  # Tree-right
 6396     # . epilogue
 6397     89/<- %esp 5/r32/ebp
 6398     5d/pop-to-ebp
 6399     c3/return
 6400 
 6401 test-function-header-with-multiple-args-and-outputs:
 6402     # . prologue
 6403     55/push-ebp
 6404     89/<- %ebp 4/r32/esp
 6405     # setup
 6406     (clear-stream _test-input-stream)
 6407     (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx: int {\n")
 6408     # result/ecx: function
 6409     2b/subtract *Function-size 4/r32/esp
 6410     89/<- %ecx 4/r32/esp
 6411     (zero-out %ecx *Function-size)
 6412     # var vars/ebx: (stack live-var 16)
 6413     81 5/subop/subtract %esp 0xc0/imm32
 6414     68/push 0xc0/imm32/size
 6415     68/push 0/imm32/top
 6416     89/<- %ebx 4/r32/esp
 6417     # convert
 6418     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 6419     # check result->name
 6420     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 6421     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args-and-outputs/name")
 6422     # var inouts/edx: (addr list var) = lookup(result->inouts)
 6423     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 6424     89/<- %edx 0/r32/eax
 6425 $test-function-header-with-multiple-args-and-outputs:inout0:
 6426     # var v/ebx: (addr var) = lookup(inouts->value)
 6427     (lookup *edx *(edx+4))  # List-value List-value => eax
 6428     89/<- %ebx 0/r32/eax
 6429     # check v->name
 6430     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 6431     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args-and-outputs/inout:0")
 6432     # check v->type
 6433     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 6434     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:0")  # Tree-is-atom
 6435     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1")  # Tree-value
 6436     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:2")  # Tree-right
 6437 $test-function-header-with-multiple-args-and-outputs:inout1:
 6438     # inouts = lookup(inouts->next)
 6439     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 6440     89/<- %edx 0/r32/eax
 6441     # v = lookup(inouts->value)
 6442     (lookup *edx *(edx+4))  # List-value List-value => eax
 6443     89/<- %ebx 0/r32/eax
 6444     # check v->name
 6445     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 6446     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args-and-outputs/inout:1")
 6447     # check v->type
 6448     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 6449     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:0")  # Tree-is-atom
 6450     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1")  # Tree-value
 6451     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:2")  # Tree-right
 6452 $test-function-header-with-multiple-args-and-outputs:inout2:
 6453     # inouts = lookup(inouts->next)
 6454     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 6455     89/<- %edx 0/r32/eax
 6456     # v = lookup(inouts->value)
 6457     (lookup *edx *(edx+4))  # List-value List-value => eax
 6458     89/<- %ebx 0/r32/eax
 6459     # check v->name
 6460     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 6461     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args-and-outputs/inout:2")
 6462     # check v->type
 6463     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 6464     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:0")  # Tree-is-atom
 6465     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1")  # Tree-value
 6466     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:2")  # Tree-right
 6467 $test-function-header-with-multiple-args-and-outputs:out0:
 6468     # var outputs/edx: (addr list var) = lookup(result->outputs)
 6469     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
 6470     89/<- %edx 0/r32/eax
 6471     # v = lookup(outputs->value)
 6472     (lookup *edx *(edx+4))  # List-value List-value => eax
 6473     89/<- %ebx 0/r32/eax
 6474     # check v->name
 6475     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 6476     (check-strings-equal %eax "x" "F - test-function-header-with-multiple-args-and-outputs/output:0")
 6477     # check v->register
 6478     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 6479     (check-strings-equal %eax "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register")
 6480     # check v->type
 6481     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 6482     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:0")  # Tree-is-atom
 6483     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1")  # Tree-value
 6484     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:2")  # Tree-right
 6485 $test-function-header-with-multiple-args-and-outputs:out1:
 6486     # outputs = lookup(outputs->next)
 6487     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 6488     89/<- %edx 0/r32/eax
 6489     # v = lookup(inouts->value)
 6490     (lookup *edx *(edx+4))  # List-value List-value => eax
 6491     89/<- %ebx 0/r32/eax
 6492     # check v->name
 6493     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 6494     (check-strings-equal %eax "y" "F - test-function-header-with-multiple-args-and-outputs/output:1")
 6495     # check v->register
 6496     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 6497     (check-strings-equal %eax "edx" "F - test-function-header-with-multiple-args-and-outputs/output:1/register")
 6498     # check v->type
 6499     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 6500     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:0")  # Tree-is-atom
 6501     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1")  # Tree-value
 6502     (check-ints-equal *(eax+0c) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:2")  # Tree-right
 6503     # . epilogue
 6504     89/<- %esp 5/r32/ebp
 6505     5d/pop-to-ebp
 6506     c3/return
 6507 
 6508 # format for variables with types
 6509 #   x: int
 6510 #   x: int,
 6511 #   x/eax: int
 6512 #   x/eax: int,
 6513 # ignores at most one trailing comma
 6514 # WARNING: modifies name
 6515 parse-var-with-type:  # name: (addr slice), first-line: (addr stream byte), out: (addr handle var), err: (addr buffered-file), ed: (addr exit-descriptor)
 6516     # pseudocode:
 6517     #   var s: slice
 6518     #   if (!slice-ends-with(name, ":"))
 6519     #     abort
 6520     #   --name->end to skip ':'
 6521     #   next-token-from-slice(name->start, name->end, '/', s)
 6522     #   new-var-from-slice(s, out)
 6523     #   ## register
 6524     #   next-token-from-slice(s->end, name->end, '/', s)
 6525     #   if (!slice-empty?(s))
 6526     #     out->register = slice-to-string(s)
 6527     #   ## type
 6528     #   var type: (handle tree type-id) = parse-type(first-line)
 6529     #   out->type = type
 6530     #
 6531     # . prologue
 6532     55/push-ebp
 6533     89/<- %ebp 4/r32/esp
 6534     # . save registers
 6535     50/push-eax
 6536     51/push-ecx
 6537     52/push-edx
 6538     53/push-ebx
 6539     56/push-esi
 6540     57/push-edi
 6541     # esi = name
 6542     8b/-> *(ebp+8) 6/r32/esi
 6543     # if (!slice-ends-with?(name, ":")) abort
 6544     8b/-> *(esi+4) 1/r32/ecx  # Slice-end
 6545     49/decrement-ecx
 6546     8a/copy-byte *ecx 1/r32/CL
 6547     81 4/subop/and %ecx 0xff/imm32
 6548     81 7/subop/compare %ecx 0x3a/imm32/colon
 6549     0f 85/jump-if-!= $parse-var-with-type:abort/disp32
 6550     # --name->end to skip ':'
 6551     ff 1/subop/decrement *(esi+4)
 6552     # var s/ecx: slice
 6553     68/push 0/imm32/end
 6554     68/push 0/imm32/start
 6555     89/<- %ecx 4/r32/esp
 6556 $parse-var-with-type:parse-name:
 6557     (next-token-from-slice *esi *(esi+4) 0x2f %ecx)  # Slice-start, Slice-end, '/'
 6558 $parse-var-with-type:create-var:
 6559     # new-var-from-slice(s, out)
 6560     (new-var-from-slice Heap %ecx *(ebp+0x10))
 6561     # save out->register
 6562 $parse-var-with-type:save-register:
 6563     # . var out-addr/edi: (addr var) = lookup(*out)
 6564     8b/-> *(ebp+0x10) 7/r32/edi
 6565     (lookup *edi *(edi+4))  # => eax
 6566     89/<- %edi 0/r32/eax
 6567     # . s = next-token(...)
 6568     (next-token-from-slice *(ecx+4) *(esi+4) 0x2f %ecx)  # s->end, name->end, '/'
 6569     # . if (!slice-empty?(s)) out->register = slice-to-string(s)
 6570     {
 6571 $parse-var-with-type:write-register:
 6572       (slice-empty? %ecx)  # => eax
 6573       3d/compare-eax-and 0/imm32/false
 6574       75/jump-if-!= break/disp8
 6575       # out->register = slice-to-string(s)
 6576       8d/copy-address *(edi+0x18) 0/r32/eax  # Var-register
 6577       (slice-to-string Heap %ecx %eax)
 6578     }
 6579 $parse-var-with-type:save-type:
 6580     8d/copy-address *(edi+8) 0/r32/eax  # Var-type
 6581     (parse-type Heap *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 6582 $parse-var-with-type:end:
 6583     # . reclaim locals
 6584     81 0/subop/add %esp 8/imm32
 6585     # . restore registers
 6586     5f/pop-to-edi
 6587     5e/pop-to-esi
 6588     5b/pop-to-ebx
 6589     5a/pop-to-edx
 6590     59/pop-to-ecx
 6591     58/pop-to-eax
 6592     # . epilogue
 6593     89/<- %esp 5/r32/ebp
 6594     5d/pop-to-ebp
 6595     c3/return
 6596 
 6597 $parse-var-with-type:abort:
 6598     # error("var should have form 'name: type' in '" line "'\n")
 6599     (write-buffered *(ebp+0x14) "var should have form 'name: type' in '")
 6600     (flush *(ebp+0x14))
 6601     (rewind-stream *(ebp+0xc))
 6602     (write-stream-data *(ebp+0x14) *(ebp+0xc))
 6603     (write-buffered *(ebp+0x14) "'\n")
 6604     (flush *(ebp+0x14))
 6605     (stop *(ebp+0x18) 1)
 6606     # never gets here
 6607 
 6608 parse-type:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle tree type-id), err: (addr buffered-file), ed: (addr exit-descriptor)
 6609     # pseudocode:
 6610     #   var s: slice = next-mu-token(in)
 6611     #   assert s != ""
 6612     #   assert s != "->"
 6613     #   assert s != "{"
 6614     #   assert s != "}"
 6615     #   if s == ")"
 6616     #     return
 6617     #   out = allocate(Tree)
 6618     #   if s != "("
 6619     #     HACK: if s is an int, parse and return it
 6620     #     out->left-is-atom? = true
 6621     #     out->value = pos-or-insert-slice(Type-id, s)
 6622     #     return
 6623     #   out->left = parse-type(ad, in)
 6624     #   out->right = parse-type-tree(ad, in)
 6625     #
 6626     # . prologue
 6627     55/push-ebp
 6628     89/<- %ebp 4/r32/esp
 6629     # . save registers
 6630     50/push-eax
 6631     51/push-ecx
 6632     52/push-edx
 6633     # clear out
 6634     (zero-out *(ebp+0x10) *Handle-size)
 6635     # var s/ecx: slice
 6636     68/push 0/imm32
 6637     68/push 0/imm32
 6638     89/<- %ecx 4/r32/esp
 6639     # s = next-mu-token(in)
 6640     (next-mu-token *(ebp+0xc) %ecx)
 6641 #?     (write-buffered Stderr "tok: ")
 6642 #?     (write-slice-buffered Stderr %ecx)
 6643 #?     (write-buffered Stderr "$\n")
 6644 #?     (flush Stderr)
 6645     # assert s != ""
 6646     (slice-equal? %ecx "")  # => eax
 6647     3d/compare-eax-and 0/imm32/false
 6648     0f 85/jump-if-!= $parse-type:abort/disp32
 6649     # assert s != "{"
 6650     (slice-equal? %ecx "{")  # => eax
 6651     3d/compare-eax-and 0/imm32/false
 6652     0f 85/jump-if-!= $parse-type:abort/disp32
 6653     # assert s != "}"
 6654     (slice-equal? %ecx "}")  # => eax
 6655     3d/compare-eax-and 0/imm32/false
 6656     0f 85/jump-if-!= $parse-type:abort/disp32
 6657     # assert s != "->"
 6658     (slice-equal? %ecx "->")  # => eax
 6659     3d/compare-eax-and 0/imm32/false
 6660     0f 85/jump-if-!= $parse-type:abort/disp32
 6661     # if (s == ")") return
 6662     (slice-equal? %ecx ")")  # => eax
 6663     3d/compare-eax-and 0/imm32/false
 6664     0f 85/jump-if-!= $parse-type:end/disp32
 6665     # out = new tree
 6666     (allocate *(ebp+8) *Tree-size *(ebp+0x10))
 6667     # var out-addr/edx: (addr tree type-id) = lookup(*out)
 6668     8b/-> *(ebp+0x10) 2/r32/edx
 6669     (lookup *edx *(edx+4))  # => eax
 6670     89/<- %edx 0/r32/eax
 6671     {
 6672       # if (s != "(") break
 6673       (slice-equal? %ecx "(")  # => eax
 6674       3d/compare-eax-and 0/imm32/false
 6675       75/jump-if-!= break/disp8
 6676       # EGREGIOUS HACK for static array sizes: if s is a number, parse it
 6677       {
 6678 $parse-type:check-for-int:
 6679         (is-hex-int? %ecx)  # => eax
 6680         3d/compare-eax-and 0/imm32/false
 6681         74/jump-if-= break/disp8
 6682 $parse-type:int:
 6683         (parse-hex-int-from-slice %ecx)  # => eax
 6684         89/<- *(edx+4) 0/r32/eax  # Tree-value
 6685         e9/jump $parse-type:end/disp32
 6686       }
 6687 $parse-type:atom:
 6688       # out->left-is-atom? = true
 6689       c7 0/subop/copy *edx 1/imm32/true  # Tree-is-atom
 6690       # out->value = pos-or-insert-slice(Type-id, s)
 6691       (pos-or-insert-slice Type-id %ecx)  # => eax
 6692       89/<- *(edx+4) 0/r32/eax  # Tree-value
 6693       e9/jump $parse-type:end/disp32
 6694     }
 6695 $parse-type:non-atom:
 6696     # otherwise s == "("
 6697     # out->left = parse-type(ad, in)
 6698     8d/copy-address *(edx+4) 0/r32/eax  # Tree-left
 6699     (parse-type *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 6700     # out->right = parse-type-tree(ad, in)
 6701     8d/copy-address *(edx+0xc) 0/r32/eax  # Tree-right
 6702     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 6703 $parse-type:end:
 6704     # . reclaim locals
 6705     81 0/subop/add %esp 8/imm32
 6706     # . restore registers
 6707     5a/pop-to-edx
 6708     59/pop-to-ecx
 6709     58/pop-to-eax
 6710     # . epilogue
 6711     89/<- %esp 5/r32/ebp
 6712     5d/pop-to-ebp
 6713     c3/return
 6714 
 6715 $parse-type:abort:
 6716     # error("unexpected token when parsing type: '" s "'\n")
 6717     (write-buffered *(ebp+0x14) "unexpected token when parsing type: '")
 6718     (write-slice-buffered *(ebp+0x14) %ecx)
 6719     (write-buffered *(ebp+0x14) "'\n")
 6720     (flush *(ebp+0x14))
 6721     (stop *(ebp+0x18) 1)
 6722     # never gets here
 6723 
 6724 parse-type-tree:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle tree type-id), err: (addr buffered-file), ed: (addr exit-descriptor)
 6725     # pseudocode:
 6726     #   var tmp: (handle tree type-id) = parse-type(ad, in)
 6727     #   if tmp == 0
 6728     #     return 0
 6729     #   out = allocate(Tree)
 6730     #   out->left = tmp
 6731     #   out->right = parse-type-tree(ad, in)
 6732     #
 6733     # . prologue
 6734     55/push-ebp
 6735     89/<- %ebp 4/r32/esp
 6736     # . save registers
 6737     50/push-eax
 6738     51/push-ecx
 6739     52/push-edx
 6740     #
 6741     (zero-out *(ebp+0x10) *Handle-size)
 6742     # var tmp/ecx: (handle tree type-id)
 6743     68/push 0/imm32
 6744     68/push 0/imm32
 6745     89/<- %ecx 4/r32/esp
 6746     # tmp = parse-type(ad, in)
 6747     (parse-type *(ebp+8) *(ebp+0xc) %ecx *(ebp+0x14) *(ebp+0x18))
 6748     # if (tmp == 0) return
 6749     81 7/subop/compare *ecx 0/imm32
 6750     74/jump-if-= $parse-type-tree:end/disp8
 6751     # out = new tree
 6752     (allocate *(ebp+8) *Tree-size *(ebp+0x10))
 6753     # var out-addr/edx: (addr tree) = lookup(*out)
 6754     8b/-> *(ebp+0x10) 2/r32/edx
 6755     (lookup *edx *(edx+4))  # => eax
 6756     89/<- %edx 0/r32/eax
 6757     # out->left = tmp
 6758     8b/-> *ecx 0/r32/eax
 6759     89/<- *(edx+4) 0/r32/eax  # Tree-left
 6760     8b/-> *(ecx+4) 0/r32/eax
 6761     89/<- *(edx+8) 0/r32/eax  # Tree-left
 6762     # out->right = parse-type-tree(ad, in)
 6763     8d/copy-address *(edx+0xc) 0/r32/eax  # Tree-right
 6764     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 6765 $parse-type-tree:end:
 6766     # . reclaim locals
 6767     81 0/subop/add %esp 8/imm32
 6768     # . restore registers
 6769     5a/pop-to-edx
 6770     59/pop-to-ecx
 6771     58/pop-to-eax
 6772     # . epilogue
 6773     89/<- %esp 5/r32/ebp
 6774     5d/pop-to-ebp
 6775     c3/return
 6776 
 6777 next-mu-token:  # in: (addr stream byte), out: (addr slice)
 6778     # pseudocode:
 6779     # start:
 6780     #   skip-chars-matching-whitespace(in)
 6781     #   if in->read >= in->write              # end of in
 6782     #     out = {0, 0}
 6783     #     return
 6784     #   out->start = &in->data[in->read]
 6785     #   var curr-byte/eax: byte = in->data[in->read]
 6786     #   if curr->byte == ','                  # comment token
 6787     #     ++in->read
 6788     #     goto start
 6789     #   if curr-byte == '#'                   # comment
 6790     #     goto done                             # treat as eof
 6791     #   if curr-byte == '"'                   # string literal
 6792     #     skip-string(in)
 6793     #     goto done                           # no metadata
 6794     #   if curr-byte == '('
 6795     #     ++in->read
 6796     #     goto done
 6797     #   if curr-byte == ')'
 6798     #     ++in->read
 6799     #     goto done
 6800     #   # read a word
 6801     #   while true
 6802     #     if in->read >= in->write
 6803     #       break
 6804     #     curr-byte = in->data[in->read]
 6805     #     if curr-byte == ' '
 6806     #       break
 6807     #     if curr-byte == '\r'
 6808     #       break
 6809     #     if curr-byte == '\n'
 6810     #       break
 6811     #     if curr-byte == '('
 6812     #       break
 6813     #     if curr-byte == ')'
 6814     #       break
 6815     #     if curr-byte == ','
 6816     #       break
 6817     #     ++in->read
 6818     # done:
 6819     #   out->end = &in->data[in->read]
 6820     #
 6821     # . prologue
 6822     55/push-ebp
 6823     89/<- %ebp 4/r32/esp
 6824     # . save registers
 6825     50/push-eax
 6826     51/push-ecx
 6827     56/push-esi
 6828     57/push-edi
 6829     # esi = in
 6830     8b/-> *(ebp+8) 6/r32/esi
 6831     # edi = out
 6832     8b/-> *(ebp+0xc) 7/r32/edi
 6833 $next-mu-token:start:
 6834     (skip-chars-matching-whitespace %esi)
 6835 $next-mu-token:check0:
 6836     # if (in->read >= in->write) return out = {0, 0}
 6837     # . ecx = in->read
 6838     8b/-> *(esi+4) 1/r32/ecx
 6839     # . if (ecx >= in->write) return out = {0, 0}
 6840     3b/compare<- *esi 1/r32/ecx
 6841     c7 0/subop/copy *edi 0/imm32
 6842     c7 0/subop/copy *(edi+4) 0/imm32
 6843     0f 8d/jump-if->= $next-mu-token:end/disp32
 6844     # out->start = &in->data[in->read]
 6845     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
 6846     89/<- *edi 0/r32/eax
 6847     # var curr-byte/eax: byte = in->data[in->read]
 6848     31/xor-with %eax 0/r32/eax
 6849     8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
 6850     {
 6851 $next-mu-token:check-for-comma:
 6852       # if (curr-byte != ',') break
 6853       3d/compare-eax-and 0x2c/imm32/comma
 6854       75/jump-if-!= break/disp8
 6855       # ++in->read
 6856       ff 0/subop/increment *(esi+4)
 6857       # restart
 6858       e9/jump $next-mu-token:start/disp32
 6859     }
 6860     {
 6861 $next-mu-token:check-for-comment:
 6862       # if (curr-byte != '#') break
 6863       3d/compare-eax-and 0x23/imm32/pound
 6864       75/jump-if-!= break/disp8
 6865       # return eof
 6866       e9/jump $next-mu-token:done/disp32
 6867     }
 6868     {
 6869 $next-mu-token:check-for-string-literal:
 6870       # if (curr-byte != '"') break
 6871       3d/compare-eax-and 0x22/imm32/dquote
 6872       75/jump-if-!= break/disp8
 6873       (skip-string %esi)
 6874       # return
 6875       e9/jump $next-mu-token:done/disp32
 6876     }
 6877     {
 6878 $next-mu-token:check-for-open-paren:
 6879       # if (curr-byte != '(') break
 6880       3d/compare-eax-and 0x28/imm32/open-paren
 6881       75/jump-if-!= break/disp8
 6882       # ++in->read
 6883       ff 0/subop/increment *(esi+4)
 6884       # return
 6885       e9/jump $next-mu-token:done/disp32
 6886     }
 6887     {
 6888 $next-mu-token:check-for-close-paren:
 6889       # if (curr-byte != ')') break
 6890       3d/compare-eax-and 0x29/imm32/close-paren
 6891       75/jump-if-!= break/disp8
 6892       # ++in->read
 6893       ff 0/subop/increment *(esi+4)
 6894       # return
 6895       e9/jump $next-mu-token:done/disp32
 6896     }
 6897     {
 6898 $next-mu-token:regular-word-without-metadata:
 6899       # if (in->read >= in->write) break
 6900       # . ecx = in->read
 6901       8b/-> *(esi+4) 1/r32/ecx
 6902       # . if (ecx >= in->write) break
 6903       3b/compare<- *esi 1/r32/ecx
 6904       7d/jump-if->= break/disp8
 6905       # var c/eax: byte = in->data[in->read]
 6906       31/xor-with %eax 0/r32/eax
 6907       8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
 6908       # if (c == ' ') break
 6909       3d/compare-eax-and 0x20/imm32/space
 6910       74/jump-if-= break/disp8
 6911       # if (c == '\r') break
 6912       3d/compare-eax-and 0xd/imm32/carriage-return
 6913       74/jump-if-= break/disp8
 6914       # if (c == '\n') break
 6915       3d/compare-eax-and 0xa/imm32/newline
 6916       74/jump-if-= break/disp8
 6917       # if (c == '(') break
 6918       3d/compare-eax-and 0x28/imm32/open-paren
 6919       0f 84/jump-if-= break/disp32
 6920       # if (c == ')') break
 6921       3d/compare-eax-and 0x29/imm32/close-paren
 6922       0f 84/jump-if-= break/disp32
 6923       # if (c == ',') break
 6924       3d/compare-eax-and 0x2c/imm32/comma
 6925       0f 84/jump-if-= break/disp32
 6926       # ++in->read
 6927       ff 0/subop/increment *(esi+4)
 6928       #
 6929       e9/jump loop/disp32
 6930     }
 6931 $next-mu-token:done:
 6932     # out->end = &in->data[in->read]
 6933     8b/-> *(esi+4) 1/r32/ecx
 6934     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
 6935     89/<- *(edi+4) 0/r32/eax
 6936 $next-mu-token:end:
 6937     # . restore registers
 6938     5f/pop-to-edi
 6939     5e/pop-to-esi
 6940     59/pop-to-ecx
 6941     58/pop-to-eax
 6942     # . epilogue
 6943     89/<- %esp 5/r32/ebp
 6944     5d/pop-to-ebp
 6945     c3/return
 6946 
 6947 pos-or-insert-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
 6948     # . prologue
 6949     55/push-ebp
 6950     89/<- %ebp 4/r32/esp
 6951     # if (pos-slice(arr, s) != -1) return it
 6952     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
 6953     3d/compare-eax-and -1/imm32
 6954     75/jump-if-!= $pos-or-insert-slice:end/disp8
 6955 $pos-or-insert-slice:insert:
 6956     # var s2/eax: (handle array byte)
 6957     68/push 0/imm32
 6958     68/push 0/imm32
 6959     89/<- %eax 4/r32/esp
 6960     (slice-to-string Heap *(ebp+0xc) %eax)
 6961     # throw away alloc-id
 6962     (lookup *eax *(eax+4))  # => eax
 6963     (write-int *(ebp+8) %eax)
 6964     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
 6965 $pos-or-insert-slice:end:
 6966     # . reclaim locals
 6967     81 0/subop/add %esp 8/imm32
 6968     # . epilogue
 6969     89/<- %esp 5/r32/ebp
 6970     5d/pop-to-ebp
 6971     c3/return
 6972 
 6973 # return the index in an array of strings matching 's', -1 if not found
 6974 # index is denominated in elements, not bytes
 6975 pos-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
 6976     # . prologue
 6977     55/push-ebp
 6978     89/<- %ebp 4/r32/esp
 6979     # . save registers
 6980     51/push-ecx
 6981     52/push-edx
 6982     53/push-ebx
 6983     56/push-esi
 6984 #?     (write-buffered Stderr "pos-slice: ")
 6985 #?     (write-slice-buffered Stderr *(ebp+0xc))
 6986 #?     (write-buffered Stderr "\n")
 6987 #?     (flush Stderr)
 6988     # esi = arr
 6989     8b/-> *(ebp+8) 6/r32/esi
 6990     # var index/ecx: int = 0
 6991     b9/copy-to-ecx 0/imm32
 6992     # var curr/edx: (addr (addr array byte)) = arr->data
 6993     8d/copy-address *(esi+0xc) 2/r32/edx
 6994     # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write]
 6995     8b/-> *esi 3/r32/ebx
 6996     8d/copy-address *(esi+ebx+0xc) 3/r32/ebx
 6997     {
 6998 #?       (write-buffered Stderr "  ")
 6999 #?       (write-int32-hex-buffered Stderr %ecx)
 7000 #?       (write-buffered Stderr "\n")
 7001 #?       (flush Stderr)
 7002       # if (curr >= max) return -1
 7003       39/compare %edx 3/r32/ebx
 7004       b8/copy-to-eax -1/imm32
 7005       73/jump-if-addr>= $pos-slice:end/disp8
 7006       # if (slice-equal?(s, *curr)) break
 7007       (slice-equal? *(ebp+0xc) *edx)  # => eax
 7008       3d/compare-eax-and 0/imm32/false
 7009       75/jump-if-!= break/disp8
 7010       # ++index
 7011       41/increment-ecx
 7012       # curr += 4
 7013       81 0/subop/add %edx 4/imm32
 7014       #
 7015       eb/jump loop/disp8
 7016     }
 7017     # return index
 7018     89/<- %eax 1/r32/ecx
 7019 $pos-slice:end:
 7020 #?     (write-buffered Stderr "=> ")
 7021 #?     (write-int32-hex-buffered Stderr %eax)
 7022 #?     (write-buffered Stderr "\n")
 7023     # . restore registers
 7024     5e/pop-to-esi
 7025     5b/pop-to-ebx
 7026     5a/pop-to-edx
 7027     59/pop-to-ecx
 7028     # . epilogue
 7029     89/<- %esp 5/r32/ebp
 7030     5d/pop-to-ebp
 7031     c3/return
 7032 
 7033 test-parse-var-with-type:
 7034     # . prologue
 7035     55/push-ebp
 7036     89/<- %ebp 4/r32/esp
 7037     # (eax..ecx) = "x:"
 7038     b8/copy-to-eax "x:"/imm32
 7039     8b/-> *eax 1/r32/ecx
 7040     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7041     05/add-to-eax 4/imm32
 7042     # var slice/ecx: slice = {eax, ecx}
 7043     51/push-ecx
 7044     50/push-eax
 7045     89/<- %ecx 4/r32/esp
 7046     # _test-input-stream contains "int"
 7047     (clear-stream _test-input-stream)
 7048     (write _test-input-stream "int")
 7049     # var v/edx: (handle var)
 7050     68/push 0/imm32
 7051     68/push 0/imm32
 7052     89/<- %edx 4/r32/esp
 7053     #
 7054     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 7055     # var v-addr/edx: (addr var) = lookup(v)
 7056     (lookup *edx *(edx+4))  # => eax
 7057     89/<- %edx 0/r32/eax
 7058     # check v-addr->name
 7059     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 7060     (check-strings-equal %eax "x" "F - test-parse-var-with-type/name")
 7061     # check v-addr->type
 7062     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 7063     (check-ints-equal *eax 1 "F - test-parse-var-with-type/type:0")  # Tree-is-atom
 7064     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type/type:1")  # Tree-value
 7065     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type/type:2")  # Tree-right
 7066     # . epilogue
 7067     89/<- %esp 5/r32/ebp
 7068     5d/pop-to-ebp
 7069     c3/return
 7070 
 7071 test-parse-var-with-type-and-register:
 7072     # . prologue
 7073     55/push-ebp
 7074     89/<- %ebp 4/r32/esp
 7075     # (eax..ecx) = "x/eax:"
 7076     b8/copy-to-eax "x/eax:"/imm32
 7077     8b/-> *eax 1/r32/ecx
 7078     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7079     05/add-to-eax 4/imm32
 7080     # var slice/ecx: slice = {eax, ecx}
 7081     51/push-ecx
 7082     50/push-eax
 7083     89/<- %ecx 4/r32/esp
 7084     # _test-input-stream contains "int"
 7085     (clear-stream _test-input-stream)
 7086     (write _test-input-stream "int")
 7087     # var v/edx: (handle var)
 7088     68/push 0/imm32
 7089     68/push 0/imm32
 7090     89/<- %edx 4/r32/esp
 7091     #
 7092     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 7093     # var v-addr/edx: (addr var) = lookup(v)
 7094     (lookup *edx *(edx+4))  # => eax
 7095     89/<- %edx 0/r32/eax
 7096     # check v-addr->name
 7097     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 7098     (check-strings-equal %eax "x" "F - test-parse-var-with-type-and-register/name")
 7099     # check v-addr->register
 7100     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 7101     (check-strings-equal %eax "eax" "F - test-parse-var-with-type-and-register/register")
 7102     # check v-addr->type
 7103     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 7104     (check-ints-equal *eax 1 "F - test-parse-var-with-type-and-register/type:0")  # Tree-is-atom
 7105     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type-and-register/type:1")  # Tree-left
 7106     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type-and-register/type:2")  # Tree-right
 7107     # . epilogue
 7108     89/<- %esp 5/r32/ebp
 7109     5d/pop-to-ebp
 7110     c3/return
 7111 
 7112 test-parse-var-with-trailing-characters:
 7113     # . prologue
 7114     55/push-ebp
 7115     89/<- %ebp 4/r32/esp
 7116     # (eax..ecx) = "x:"
 7117     b8/copy-to-eax "x:"/imm32
 7118     8b/-> *eax 1/r32/ecx
 7119     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7120     05/add-to-eax 4/imm32
 7121     # var slice/ecx: slice = {eax, ecx}
 7122     51/push-ecx
 7123     50/push-eax
 7124     89/<- %ecx 4/r32/esp
 7125     # _test-input-stream contains "int,"
 7126     (clear-stream _test-input-stream)
 7127     (write _test-input-stream "int,")
 7128     # var v/edx: (handle var)
 7129     68/push 0/imm32
 7130     68/push 0/imm32
 7131     89/<- %edx 4/r32/esp
 7132     #
 7133     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 7134     # var v-addr/edx: (addr var) = lookup(v)
 7135     (lookup *edx *(edx+4))  # => eax
 7136     89/<- %edx 0/r32/eax
 7137     # check v-addr->name
 7138     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 7139     (check-strings-equal %eax "x" "F - test-parse-var-with-trailing-characters/name")
 7140     # check v-addr->register
 7141     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-trailing-characters/register")  # Var-register
 7142     # check v-addr->type
 7143     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 7144     (check-ints-equal *eax 1 "F - test-parse-var-with-trailing-characters/type:0")  # Tree-is-atom
 7145     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-trailing-characters/type:1")  # Tree-left
 7146     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-trailing-characters/type:1")  # Tree-right
 7147     # . epilogue
 7148     89/<- %esp 5/r32/ebp
 7149     5d/pop-to-ebp
 7150     c3/return
 7151 
 7152 test-parse-var-with-register-and-trailing-characters:
 7153     # . prologue
 7154     55/push-ebp
 7155     89/<- %ebp 4/r32/esp
 7156     # (eax..ecx) = "x/eax:"
 7157     b8/copy-to-eax "x/eax:"/imm32
 7158     8b/-> *eax 1/r32/ecx
 7159     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7160     05/add-to-eax 4/imm32
 7161     # var slice/ecx: slice = {eax, ecx}
 7162     51/push-ecx
 7163     50/push-eax
 7164     89/<- %ecx 4/r32/esp
 7165     # _test-input-stream contains "int,"
 7166     (clear-stream _test-input-stream)
 7167     (write _test-input-stream "int,")
 7168     # var v/edx: (handle var)
 7169     68/push 0/imm32
 7170     68/push 0/imm32
 7171     89/<- %edx 4/r32/esp
 7172     #
 7173     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 7174     # var v-addr/edx: (addr var) = lookup(v)
 7175     (lookup *edx *(edx+4))  # => eax
 7176     89/<- %edx 0/r32/eax
 7177     # check v-addr->name
 7178     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 7179     (check-strings-equal %eax "x" "F - test-parse-var-with-register-and-trailing-characters/name")
 7180     # check v-addr->register
 7181     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 7182     (check-strings-equal %eax "eax" "F - test-parse-var-with-register-and-trailing-characters/register")
 7183     # check v-addr->type
 7184     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 7185     (check-ints-equal *eax 1 "F - test-parse-var-with-register-and-trailing-characters/type:0")  # Tree-is-atom
 7186     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-register-and-trailing-characters/type:1")  # Tree-left
 7187     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-register-and-trailing-characters/type:2")  # Tree-right
 7188     # . epilogue
 7189     89/<- %esp 5/r32/ebp
 7190     5d/pop-to-ebp
 7191     c3/return
 7192 
 7193 test-parse-var-with-compound-type:
 7194     # . prologue
 7195     55/push-ebp
 7196     89/<- %ebp 4/r32/esp
 7197     # (eax..ecx) = "x:"
 7198     b8/copy-to-eax "x:"/imm32
 7199     8b/-> *eax 1/r32/ecx
 7200     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7201     05/add-to-eax 4/imm32
 7202     # var slice/ecx: slice = {eax, ecx}
 7203     51/push-ecx
 7204     50/push-eax
 7205     89/<- %ecx 4/r32/esp
 7206     # _test-input-stream contains "(addr int)"
 7207     (clear-stream _test-input-stream)
 7208     (write _test-input-stream "(addr int)")
 7209     # var v/edx: (handle var)
 7210     68/push 0/imm32
 7211     68/push 0/imm32
 7212     89/<- %edx 4/r32/esp
 7213     #
 7214     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 7215     # var v-addr/edx: (addr var) = lookup(v)
 7216     (lookup *edx *(edx+4))  # => eax
 7217     89/<- %edx 0/r32/eax
 7218     # check v-addr->name
 7219     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 7220     (check-strings-equal %eax "x" "F - test-parse-var-with-compound-type/name")
 7221     # check v-addr->register
 7222     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-compound-type/register")  # Var-register
 7223     # - check v-addr->type
 7224     # var type/edx: (addr tree type-id) = var->type
 7225     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 7226     89/<- %edx 0/r32/eax
 7227     # type is a non-atom
 7228     (check-ints-equal *edx 0 "F - test-parse-var-with-compound-type/type:0")  # Tree-is-atom
 7229     # type->left == atom(addr)
 7230     (lookup *(edx+4) *(edx+8))  # Tree-left Tree-left => eax
 7231     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:1")  # Tree-is-atom
 7232     (check-ints-equal *(eax+4) 2 "F - test-parse-var-with-compound-type/type:2")  # Tree-value
 7233     # type->right->left == atom(int)
 7234     (lookup *(edx+0xc) *(edx+0x10))  # Tree-right Tree-right => eax
 7235     (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
 7236     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:3")  # Tree-is-atom
 7237     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-compound-type/type:4")  # Tree-value
 7238     # type->right->right == null
 7239     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-compound-type/type:5")  # Tree-right
 7240     # . epilogue
 7241     89/<- %esp 5/r32/ebp
 7242     5d/pop-to-ebp
 7243     c3/return
 7244 
 7245 # identifier starts with a letter or '$' or '_'
 7246 # no constraints at the moment on later letters
 7247 # all we really want to do so far is exclude '{', '}' and '->'
 7248 is-identifier?:  # in: (addr slice) -> result/eax: boolean
 7249     # . prologue
 7250     55/push-ebp
 7251     89/<- %ebp 4/r32/esp
 7252     # if (slice-empty?(in)) return false
 7253     (slice-empty? *(ebp+8))  # => eax
 7254     3d/compare-eax-and 0/imm32/false
 7255     75/jump-if-!= $is-identifier?:false/disp8
 7256     # var c/eax: byte = *in->start
 7257     8b/-> *(ebp+8) 0/r32/eax
 7258     8b/-> *eax 0/r32/eax
 7259     8a/copy-byte *eax 0/r32/AL
 7260     81 4/subop/and %eax 0xff/imm32
 7261     # if (c == '$') return true
 7262     3d/compare-eax-and 0x24/imm32/$
 7263     74/jump-if-= $is-identifier?:true/disp8
 7264     # if (c == '_') return true
 7265     3d/compare-eax-and 0x5f/imm32/_
 7266     74/jump-if-= $is-identifier?:true/disp8
 7267     # drop case
 7268     25/and-eax-with 0x5f/imm32
 7269     # if (c < 'A') return false
 7270     3d/compare-eax-and 0x41/imm32/A
 7271     7c/jump-if-< $is-identifier?:false/disp8
 7272     # if (c > 'Z') return false
 7273     3d/compare-eax-and 0x5a/imm32/Z
 7274     7f/jump-if-> $is-identifier?:false/disp8
 7275     # otherwise return true
 7276 $is-identifier?:true:
 7277     b8/copy-to-eax 1/imm32/true
 7278     eb/jump $is-identifier?:end/disp8
 7279 $is-identifier?:false:
 7280     b8/copy-to-eax 0/imm32/false
 7281 $is-identifier?:end:
 7282     # . epilogue
 7283     89/<- %esp 5/r32/ebp
 7284     5d/pop-to-ebp
 7285     c3/return
 7286 
 7287 test-is-identifier-dollar:
 7288     # . prologue
 7289     55/push-ebp
 7290     89/<- %ebp 4/r32/esp
 7291     # (eax..ecx) = "$a"
 7292     b8/copy-to-eax "$a"/imm32
 7293     8b/-> *eax 1/r32/ecx
 7294     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7295     05/add-to-eax 4/imm32
 7296     # var slice/ecx: slice = {eax, ecx}
 7297     51/push-ecx
 7298     50/push-eax
 7299     89/<- %ecx 4/r32/esp
 7300     #
 7301     (is-identifier? %ecx)
 7302     (check-ints-equal %eax 1 "F - test-is-identifier-dollar")
 7303     # . epilogue
 7304     89/<- %esp 5/r32/ebp
 7305     5d/pop-to-ebp
 7306     c3/return
 7307 
 7308 test-is-identifier-underscore:
 7309     # . prologue
 7310     55/push-ebp
 7311     89/<- %ebp 4/r32/esp
 7312     # (eax..ecx) = "_a"
 7313     b8/copy-to-eax "_a"/imm32
 7314     8b/-> *eax 1/r32/ecx
 7315     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7316     05/add-to-eax 4/imm32
 7317     # var slice/ecx: slice = {eax, ecx}
 7318     51/push-ecx
 7319     50/push-eax
 7320     89/<- %ecx 4/r32/esp
 7321     #
 7322     (is-identifier? %ecx)
 7323     (check-ints-equal %eax 1 "F - test-is-identifier-underscore")
 7324     # . epilogue
 7325     89/<- %esp 5/r32/ebp
 7326     5d/pop-to-ebp
 7327     c3/return
 7328 
 7329 test-is-identifier-a:
 7330     # . prologue
 7331     55/push-ebp
 7332     89/<- %ebp 4/r32/esp
 7333     # (eax..ecx) = "a$"
 7334     b8/copy-to-eax "a$"/imm32
 7335     8b/-> *eax 1/r32/ecx
 7336     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7337     05/add-to-eax 4/imm32
 7338     # var slice/ecx: slice = {eax, ecx}
 7339     51/push-ecx
 7340     50/push-eax
 7341     89/<- %ecx 4/r32/esp
 7342     #
 7343     (is-identifier? %ecx)
 7344     (check-ints-equal %eax 1 "F - test-is-identifier-a")
 7345     # . epilogue
 7346     89/<- %esp 5/r32/ebp
 7347     5d/pop-to-ebp
 7348     c3/return
 7349 
 7350 test-is-identifier-z:
 7351     # . prologue
 7352     55/push-ebp
 7353     89/<- %ebp 4/r32/esp
 7354     # (eax..ecx) = "z$"
 7355     b8/copy-to-eax "z$"/imm32
 7356     8b/-> *eax 1/r32/ecx
 7357     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7358     05/add-to-eax 4/imm32
 7359     # var slice/ecx: slice = {eax, ecx}
 7360     51/push-ecx
 7361     50/push-eax
 7362     89/<- %ecx 4/r32/esp
 7363     #
 7364     (is-identifier? %ecx)
 7365     (check-ints-equal %eax 1 "F - test-is-identifier-z")
 7366     # . epilogue
 7367     89/<- %esp 5/r32/ebp
 7368     5d/pop-to-ebp
 7369     c3/return
 7370 
 7371 test-is-identifier-A:
 7372     # . prologue
 7373     55/push-ebp
 7374     89/<- %ebp 4/r32/esp
 7375     # (eax..ecx) = "A$"
 7376     b8/copy-to-eax "A$"/imm32
 7377     8b/-> *eax 1/r32/ecx
 7378     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7379     05/add-to-eax 4/imm32
 7380     # var slice/ecx: slice = {eax, ecx}
 7381     51/push-ecx
 7382     50/push-eax
 7383     89/<- %ecx 4/r32/esp
 7384     #
 7385     (is-identifier? %ecx)
 7386     (check-ints-equal %eax 1 "F - test-is-identifier-A")
 7387     # . epilogue
 7388     89/<- %esp 5/r32/ebp
 7389     5d/pop-to-ebp
 7390     c3/return
 7391 
 7392 test-is-identifier-Z:
 7393     # . prologue
 7394     55/push-ebp
 7395     89/<- %ebp 4/r32/esp
 7396     # (eax..ecx) = "Z$"
 7397     b8/copy-to-eax "Z$"/imm32
 7398     8b/-> *eax 1/r32/ecx
 7399     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7400     05/add-to-eax 4/imm32
 7401     # var slice/ecx: slice = {eax, ecx}
 7402     51/push-ecx
 7403     50/push-eax
 7404     89/<- %ecx 4/r32/esp
 7405     #
 7406     (is-identifier? %ecx)
 7407     (check-ints-equal %eax 1 "F - test-is-identifier-Z")
 7408     # . epilogue
 7409     89/<- %esp 5/r32/ebp
 7410     5d/pop-to-ebp
 7411     c3/return
 7412 
 7413 test-is-identifier-at:
 7414     # character before 'A' is invalid
 7415     # . prologue
 7416     55/push-ebp
 7417     89/<- %ebp 4/r32/esp
 7418     # (eax..ecx) = "@a"
 7419     b8/copy-to-eax "@a"/imm32
 7420     8b/-> *eax 1/r32/ecx
 7421     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7422     05/add-to-eax 4/imm32
 7423     # var slice/ecx: slice = {eax, ecx}
 7424     51/push-ecx
 7425     50/push-eax
 7426     89/<- %ecx 4/r32/esp
 7427     #
 7428     (is-identifier? %ecx)
 7429     (check-ints-equal %eax 0 "F - test-is-identifier-@")
 7430     # . epilogue
 7431     89/<- %esp 5/r32/ebp
 7432     5d/pop-to-ebp
 7433     c3/return
 7434 
 7435 test-is-identifier-square-bracket:
 7436     # character after 'Z' is invalid
 7437     # . prologue
 7438     55/push-ebp
 7439     89/<- %ebp 4/r32/esp
 7440     # (eax..ecx) = "[a"
 7441     b8/copy-to-eax "[a"/imm32
 7442     8b/-> *eax 1/r32/ecx
 7443     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7444     05/add-to-eax 4/imm32
 7445     # var slice/ecx: slice = {eax, ecx}
 7446     51/push-ecx
 7447     50/push-eax
 7448     89/<- %ecx 4/r32/esp
 7449     #
 7450     (is-identifier? %ecx)
 7451     (check-ints-equal %eax 0 "F - test-is-identifier-@")
 7452     # . epilogue
 7453     89/<- %esp 5/r32/ebp
 7454     5d/pop-to-ebp
 7455     c3/return
 7456 
 7457 test-is-identifier-backtick:
 7458     # character before 'a' is invalid
 7459     # . prologue
 7460     55/push-ebp
 7461     89/<- %ebp 4/r32/esp
 7462     # (eax..ecx) = "`a"
 7463     b8/copy-to-eax "`a"/imm32
 7464     8b/-> *eax 1/r32/ecx
 7465     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7466     05/add-to-eax 4/imm32
 7467     # var slice/ecx: slice = {eax, ecx}
 7468     51/push-ecx
 7469     50/push-eax
 7470     89/<- %ecx 4/r32/esp
 7471     #
 7472     (is-identifier? %ecx)
 7473     (check-ints-equal %eax 0 "F - test-is-identifier-backtick")
 7474     # . epilogue
 7475     89/<- %esp 5/r32/ebp
 7476     5d/pop-to-ebp
 7477     c3/return
 7478 
 7479 test-is-identifier-curly-brace-open:
 7480     # character after 'z' is invalid; also used for blocks
 7481     # . prologue
 7482     55/push-ebp
 7483     89/<- %ebp 4/r32/esp
 7484     # (eax..ecx) = "{a"
 7485     b8/copy-to-eax "{a"/imm32
 7486     8b/-> *eax 1/r32/ecx
 7487     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7488     05/add-to-eax 4/imm32
 7489     # var slice/ecx: slice = {eax, ecx}
 7490     51/push-ecx
 7491     50/push-eax
 7492     89/<- %ecx 4/r32/esp
 7493     #
 7494     (is-identifier? %ecx)
 7495     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open")
 7496     # . epilogue
 7497     89/<- %esp 5/r32/ebp
 7498     5d/pop-to-ebp
 7499     c3/return
 7500 
 7501 test-is-identifier-curly-brace-close:
 7502     # . prologue
 7503     55/push-ebp
 7504     89/<- %ebp 4/r32/esp
 7505     # (eax..ecx) = "}a"
 7506     b8/copy-to-eax "}a"/imm32
 7507     8b/-> *eax 1/r32/ecx
 7508     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7509     05/add-to-eax 4/imm32
 7510     # var slice/ecx: slice = {eax, ecx}
 7511     51/push-ecx
 7512     50/push-eax
 7513     89/<- %ecx 4/r32/esp
 7514     #
 7515     (is-identifier? %ecx)
 7516     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close")
 7517     # . epilogue
 7518     89/<- %esp 5/r32/ebp
 7519     5d/pop-to-ebp
 7520     c3/return
 7521 
 7522 test-is-identifier-hyphen:
 7523     # disallow leading '-' since '->' has special meaning
 7524     # . prologue
 7525     55/push-ebp
 7526     89/<- %ebp 4/r32/esp
 7527     # (eax..ecx) = "-a"
 7528     b8/copy-to-eax "-a"/imm32
 7529     8b/-> *eax 1/r32/ecx
 7530     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7531     05/add-to-eax 4/imm32
 7532     # var slice/ecx: slice = {eax, ecx}
 7533     51/push-ecx
 7534     50/push-eax
 7535     89/<- %ecx 4/r32/esp
 7536     #
 7537     (is-identifier? %ecx)
 7538     (check-ints-equal %eax 0 "F - test-is-identifier-hyphen")
 7539     # . epilogue
 7540     89/<- %esp 5/r32/ebp
 7541     5d/pop-to-ebp
 7542     c3/return
 7543 
 7544 populate-mu-function-body:  # in: (addr buffered-file), out: (addr function), vars: (addr stack live-var), err: (addr buffered-file), ed: (addr exit-descriptor)
 7545     # . prologue
 7546     55/push-ebp
 7547     89/<- %ebp 4/r32/esp
 7548     # . save registers
 7549     50/push-eax
 7550     56/push-esi
 7551     57/push-edi
 7552     # esi = in
 7553     8b/-> *(ebp+8) 6/r32/esi
 7554     # edi = out
 7555     8b/-> *(ebp+0xc) 7/r32/edi
 7556     # initialize some global state
 7557     c7 0/subop/copy *Curr-block-depth 1/imm32
 7558     # parse-mu-block(in, vars, out, out->body)
 7559     8d/copy-address *(edi+0x18) 0/r32/eax  # Function-body
 7560     (parse-mu-block %esi *(ebp+0x10) %edi %eax *(ebp+0x14) *(ebp+0x18))
 7561 $populate-mu-function-body:end:
 7562     # . restore registers
 7563     5f/pop-to-edi
 7564     5e/pop-to-esi
 7565     58/pop-to-eax
 7566     # . epilogue
 7567     89/<- %esp 5/r32/ebp
 7568     5d/pop-to-ebp
 7569     c3/return
 7570 
 7571 # parses a block, assuming that the leading '{' has already been read by the caller
 7572 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)
 7573     # pseudocode:
 7574     #   var line: (stream byte 512)
 7575     #   var word-slice: slice
 7576     #   allocate(Heap, Stmt-size, out)
 7577     #   var out-addr: (addr block) = lookup(*out)
 7578     #   out-addr->tag = 0/block
 7579     #   out-addr->var = some unique name
 7580     #   push(vars, {out-addr->var, false})
 7581     #   while true                                  # line loop
 7582     #     clear-stream(line)
 7583     #     read-line-buffered(in, line)
 7584     #     if (line->write == 0) break               # end of file
 7585     #     word-slice = next-mu-token(line)
 7586     #     if slice-empty?(word-slice)               # end of line
 7587     #       continue
 7588     #     else if slice-starts-with?(word-slice, "#")
 7589     #       continue
 7590     #     else if slice-equal?(word-slice, "{")
 7591     #       assert(no-tokens-in(line))
 7592     #       block = parse-mu-block(in, vars, fn)
 7593     #       append-to-block(out-addr, block)
 7594     #     else if slice-equal?(word-slice, "}")
 7595     #       break
 7596     #     else if slice-ends-with?(word-slice, ":")
 7597     #       # TODO: error-check the rest of 'line'
 7598     #       --word-slice->end to skip ':'
 7599     #       named-block = parse-mu-named-block(word-slice, in, vars, fn)
 7600     #       append-to-block(out-addr, named-block)
 7601     #     else if slice-equal?(word-slice, "var")
 7602     #       var-def = parse-mu-var-def(line, vars, fn)
 7603     #       append-to-block(out-addr, var-def)
 7604     #     else
 7605     #       stmt = parse-mu-stmt(line, vars, fn)
 7606     #       append-to-block(out-addr, stmt)
 7607     #   pop(vars)
 7608     #
 7609     # . prologue
 7610     55/push-ebp
 7611     89/<- %ebp 4/r32/esp
 7612     # . save registers
 7613     50/push-eax
 7614     51/push-ecx
 7615     52/push-edx
 7616     53/push-ebx
 7617     57/push-edi
 7618     # var line/ecx: (stream byte 512)
 7619     81 5/subop/subtract %esp 0x200/imm32
 7620     68/push 0x200/imm32/size
 7621     68/push 0/imm32/read
 7622     68/push 0/imm32/write
 7623     89/<- %ecx 4/r32/esp
 7624     # var word-slice/edx: slice
 7625     68/push 0/imm32/end
 7626     68/push 0/imm32/start
 7627     89/<- %edx 4/r32/esp
 7628     # allocate into out
 7629     (allocate Heap *Stmt-size *(ebp+0x14))
 7630     # var out-addr/edi: (addr block) = lookup(*out)
 7631     8b/-> *(ebp+0x14) 7/r32/edi
 7632     (lookup *edi *(edi+4))  # => eax
 7633     89/<- %edi 0/r32/eax
 7634     # out-addr->tag is 0 (block) by default
 7635     # set out-addr->var
 7636     8d/copy-address *(edi+0xc) 0/r32/eax  # Block-var
 7637     (new-block-name *(ebp+0x10) %eax)
 7638     # push(vars, out-addr->var)
 7639     (push *(ebp+0xc) *(edi+0xc))  # Block-var
 7640     (push *(ebp+0xc) *(edi+0x10))  # Block-var
 7641     (push *(ebp+0xc) 0)  # false
 7642     # increment *Curr-block-depth
 7643     ff 0/subop/increment *Curr-block-depth
 7644     {
 7645 $parse-mu-block:line-loop:
 7646       # line = read-line-buffered(in)
 7647       (clear-stream %ecx)
 7648       (read-line-buffered *(ebp+8) %ecx)
 7649 #?       (write-buffered Stderr "line: ")
 7650 #?       (write-stream-data Stderr %ecx)
 7651 #? #?       (write-buffered Stderr Newline)  # line has its own newline
 7652 #?       (flush Stderr)
 7653 #?       (rewind-stream %ecx)
 7654       # if (line->write == 0) break
 7655       81 7/subop/compare *ecx 0/imm32
 7656       0f 84/jump-if-= break/disp32
 7657 #?       (write-buffered Stderr "vars:\n")
 7658 #?       (dump-vars *(ebp+0xc))
 7659       # word-slice = next-mu-token(line)
 7660       (next-mu-token %ecx %edx)
 7661 #?       (write-buffered Stderr "word: ")
 7662 #?       (write-slice-buffered Stderr %edx)
 7663 #?       (write-buffered Stderr Newline)
 7664 #?       (flush Stderr)
 7665       # if slice-empty?(word-slice) continue
 7666       (slice-empty? %edx)
 7667       3d/compare-eax-and 0/imm32/false
 7668       0f 85/jump-if-!= loop/disp32
 7669       # if (slice-starts-with?(word-slice, '#') continue
 7670       # . eax = *word-slice->start
 7671       8b/-> *edx 0/r32/eax
 7672       8a/copy-byte *eax 0/r32/AL
 7673       81 4/subop/and %eax 0xff/imm32
 7674       # . if (eax == '#') continue
 7675       3d/compare-eax-and 0x23/imm32/hash
 7676       0f 84/jump-if-= loop/disp32
 7677       # if slice-equal?(word-slice, "{")
 7678       {
 7679 $parse-mu-block:check-for-block:
 7680         (slice-equal? %edx "{")
 7681         3d/compare-eax-and 0/imm32/false
 7682         74/jump-if-= break/disp8
 7683         (check-no-tokens-left %ecx)
 7684         # parse new block and append
 7685         # . var tmp/eax: (handle block)
 7686         68/push 0/imm32
 7687         68/push 0/imm32
 7688         89/<- %eax 4/r32/esp
 7689         # .
 7690         (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 7691         (append-to-block Heap %edi  *eax *(eax+4))
 7692         # . reclaim tmp
 7693         81 0/subop/add %esp 8/imm32
 7694         # .
 7695         e9/jump $parse-mu-block:line-loop/disp32
 7696       }
 7697       # if slice-equal?(word-slice, "}") break
 7698 $parse-mu-block:check-for-end:
 7699       (slice-equal? %edx "}")
 7700       3d/compare-eax-and 0/imm32/false
 7701       0f 85/jump-if-!= break/disp32
 7702       # if slice-ends-with?(word-slice, ":") parse named block and append
 7703       {
 7704 $parse-mu-block:check-for-named-block:
 7705         # . eax = *(word-slice->end-1)
 7706         8b/-> *(edx+4) 0/r32/eax
 7707         48/decrement-eax
 7708         8a/copy-byte *eax 0/r32/AL
 7709         81 4/subop/and %eax 0xff/imm32
 7710         # . if (eax != ':') break
 7711         3d/compare-eax-and 0x3a/imm32/colon
 7712         0f 85/jump-if-!= break/disp32
 7713         # TODO: error-check the rest of 'line'
 7714         #
 7715         # skip ':'
 7716         ff 1/subop/decrement *(edx+4)  # Slice-end
 7717         # var tmp/eax: (handle block)
 7718         68/push 0/imm32
 7719         68/push 0/imm32
 7720         89/<- %eax 4/r32/esp
 7721         #
 7722         (parse-mu-named-block %edx *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 7723         (append-to-block Heap %edi  *eax *(eax+4))
 7724         # reclaim tmp
 7725         81 0/subop/add %esp 8/imm32
 7726         #
 7727         e9/jump $parse-mu-block:line-loop/disp32
 7728       }
 7729       # if slice-equal?(word-slice, "var")
 7730       {
 7731 $parse-mu-block:check-for-var:
 7732         (slice-equal? %edx "var")
 7733         3d/compare-eax-and 0/imm32/false
 7734         74/jump-if-= break/disp8
 7735         # var tmp/eax: (handle block)
 7736         68/push 0/imm32
 7737         68/push 0/imm32
 7738         89/<- %eax 4/r32/esp
 7739         #
 7740         (parse-mu-var-def %ecx *(ebp+0xc) %eax *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
 7741         (append-to-block Heap %edi  *eax *(eax+4))
 7742         # reclaim tmp
 7743         81 0/subop/add %esp 8/imm32
 7744         #
 7745         e9/jump $parse-mu-block:line-loop/disp32
 7746       }
 7747 $parse-mu-block:regular-stmt:
 7748       # otherwise
 7749       # var tmp/eax: (handle block)
 7750       68/push 0/imm32
 7751       68/push 0/imm32
 7752       89/<- %eax 4/r32/esp
 7753       #
 7754       (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 7755       (append-to-block Heap %edi  *eax *(eax+4))
 7756       # reclaim tmp
 7757       81 0/subop/add %esp 8/imm32
 7758       #
 7759       e9/jump loop/disp32
 7760     } # end line loop
 7761     (clean-up-blocks *(ebp+0xc) *Curr-block-depth *(ebp+0x10))
 7762     # decrement *Curr-block-depth
 7763     ff 1/subop/decrement *Curr-block-depth
 7764     # pop(vars)
 7765     (pop *(ebp+0xc))  # => eax
 7766     (pop *(ebp+0xc))  # => eax
 7767     (pop *(ebp+0xc))  # => eax
 7768 $parse-mu-block:end:
 7769     # . reclaim locals
 7770     81 0/subop/add %esp 0x214/imm32
 7771     # . restore registers
 7772     5f/pop-to-edi
 7773     5b/pop-to-ebx
 7774     5a/pop-to-edx
 7775     59/pop-to-ecx
 7776     58/pop-to-eax
 7777     # . epilogue
 7778     89/<- %esp 5/r32/ebp
 7779     5d/pop-to-ebp
 7780     c3/return
 7781 
 7782 $parse-mu-block:abort:
 7783     # error("'{' or '}' should be on its own line, but got '")
 7784     (write-buffered *(ebp+0x18) "'{' or '}' should be on its own line, but got '")
 7785     (rewind-stream %ecx)
 7786     (write-stream-data *(ebp+0x18) %ecx)
 7787     (write-buffered *(ebp+0x18) "'\n")
 7788     (flush *(ebp+0x18))
 7789     (stop *(ebp+0x1c) 1)
 7790     # never gets here
 7791 
 7792 new-block-name:  # fn: (addr function), out: (addr handle var)
 7793     # . prologue
 7794     55/push-ebp
 7795     89/<- %ebp 4/r32/esp
 7796     # . save registers
 7797     50/push-eax
 7798     51/push-ecx
 7799     52/push-edx
 7800     # var n/ecx: int = len(fn->name) + 10 for an int + 2 for '$:'
 7801     8b/-> *(ebp+8) 0/r32/eax
 7802     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 7803     8b/-> *eax 0/r32/eax  # String-size
 7804     05/add-to-eax 0xd/imm32  # 10 + 2 for '$:'
 7805     89/<- %ecx 0/r32/eax
 7806     # var name/edx: (stream byte n)
 7807     29/subtract-from %esp 1/r32/ecx
 7808     ff 6/subop/push %ecx
 7809     68/push 0/imm32/read
 7810     68/push 0/imm32/write
 7811     89/<- %edx 4/r32/esp
 7812     (clear-stream %edx)
 7813     # eax = fn->name
 7814     8b/-> *(ebp+8) 0/r32/eax
 7815     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 7816     # construct result using Next-block-index (and increment it)
 7817     (write %edx "$")
 7818     (write %edx %eax)
 7819     (write %edx ":")
 7820     (write-int32-hex %edx *Next-block-index)
 7821     ff 0/subop/increment *Next-block-index
 7822     # var s/eax: slice = {name->data, name->data + name->write}  (clobbering edx)
 7823     # . eax = name->write
 7824     8b/-> *edx 0/r32/eax
 7825     # . edx = name->data
 7826     8d/copy-address *(edx+0xc) 2/r32/edx
 7827     # . eax = name->write + name->data
 7828     01/add-to %eax 2/r32/edx
 7829     # . push {edx, eax}
 7830     ff 6/subop/push %eax
 7831     ff 6/subop/push %edx
 7832     89/<- %eax 4/r32/esp
 7833     # out = new literal(s)
 7834     (new-literal Heap %eax *(ebp+0xc))
 7835 #?     8b/-> *(ebp+0xc) 0/r32/eax
 7836 #?     (write-buffered Stderr "type allocid in caller after new-literal: ")
 7837 #?     (write-int32-hex-buffered Stderr *(eax+8))
 7838 #?     (write-buffered Stderr " for var ")
 7839 #?     (write-int32-hex-buffered Stderr %eax)
 7840 #?     (write-buffered Stderr Newline)
 7841 #?     (flush Stderr)
 7842 $new-block-name:end:
 7843     # . reclaim locals
 7844     81 0/subop/add %ecx 0xc/imm32  # name.{read/write/len}
 7845     81 0/subop/add %ecx 8/imm32  # slice
 7846     01/add-to %esp 1/r32/ecx
 7847     # . restore registers
 7848     5a/pop-to-edx
 7849     59/pop-to-ecx
 7850     58/pop-to-eax
 7851     # . epilogue
 7852     89/<- %esp 5/r32/ebp
 7853     5d/pop-to-ebp
 7854     c3/return
 7855 
 7856 check-no-tokens-left:  # line: (addr stream byte)
 7857     # . prologue
 7858     55/push-ebp
 7859     89/<- %ebp 4/r32/esp
 7860     # . save registers
 7861     50/push-eax
 7862     51/push-ecx
 7863     # var s/ecx: slice
 7864     68/push 0/imm32/end
 7865     68/push 0/imm32/start
 7866     89/<- %ecx 4/r32/esp
 7867     #
 7868     (next-mu-token *(ebp+8) %ecx)
 7869     # if slice-empty?(s) return
 7870     (slice-empty? %ecx)
 7871     3d/compare-eax-and 0/imm32/false
 7872     75/jump-if-!= $check-no-tokens-left:end/disp8
 7873     # if (slice-starts-with?(s, '#') return
 7874     # . eax = *s->start
 7875     8b/-> *edx 0/r32/eax
 7876     8a/copy-byte *eax 0/r32/AL
 7877     81 4/subop/and %eax 0xff/imm32
 7878     # . if (eax == '#') continue
 7879     3d/compare-eax-and 0x23/imm32/hash
 7880     74/jump-if-= $check-no-tokens-left:end/disp8
 7881     # abort
 7882     (write-buffered Stderr "'{' or '}' should be on its own line, but got '")
 7883     (rewind-stream %ecx)
 7884     (write-stream 2 %ecx)
 7885     (write-buffered Stderr "'\n")
 7886     (flush Stderr)
 7887     # . syscall(exit, 1)
 7888     bb/copy-to-ebx  1/imm32
 7889     e8/call syscall_exit/disp32
 7890     # never gets here
 7891 $check-no-tokens-left:end:
 7892     # . reclaim locals
 7893     81 0/subop/add %esp 8/imm32
 7894     # . restore registers
 7895     59/pop-to-ecx
 7896     58/pop-to-eax
 7897     # . epilogue
 7898     89/<- %esp 5/r32/ebp
 7899     5d/pop-to-ebp
 7900     c3/return
 7901 
 7902 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)
 7903     # pseudocode:
 7904     #   var v: (handle var)
 7905     #   new-literal(name, v)
 7906     #   push(vars, {v, false})
 7907     #   parse-mu-block(in, vars, fn, out)
 7908     #   pop(vars)
 7909     #   out->tag = block
 7910     #   out->var = v
 7911     #
 7912     # . prologue
 7913     55/push-ebp
 7914     89/<- %ebp 4/r32/esp
 7915     # . save registers
 7916     50/push-eax
 7917     51/push-ecx
 7918     57/push-edi
 7919     # var v/ecx: (handle var)
 7920     68/push 0/imm32
 7921     68/push 0/imm32
 7922     89/<- %ecx 4/r32/esp
 7923     #
 7924     (new-literal Heap *(ebp+8) %ecx)
 7925     # push(vars, v)
 7926     (push *(ebp+0x10) *ecx)
 7927     (push *(ebp+0x10) *(ecx+4))
 7928     (push *(ebp+0x10) 0)  # false
 7929     #
 7930     (parse-mu-block *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20))
 7931     # pop v off vars
 7932     (pop *(ebp+0x10))  # => eax
 7933     (pop *(ebp+0x10))  # => eax
 7934     (pop *(ebp+0x10))  # => eax
 7935     # var out-addr/edi: (addr stmt) = lookup(*out)
 7936     8b/-> *(ebp+0x18) 7/r32/edi
 7937     (lookup *edi *(edi+4))  # => eax
 7938     89/<- %edi 0/r32/eax
 7939     # out-addr->tag = named-block
 7940     c7 0/subop/copy *edi 0/imm32/block  # Stmt-tag
 7941     # out-addr->var = v
 7942     8b/-> *ecx 0/r32/eax
 7943     89/<- *(edi+0xc) 0/r32/eax  # Block-var
 7944     8b/-> *(ecx+4) 0/r32/eax
 7945     89/<- *(edi+0x10) 0/r32/eax  # Block-var
 7946 $parse-mu-named-block:end:
 7947     # . reclaim locals
 7948     81 0/subop/add %esp 8/imm32
 7949     # . restore registers
 7950     5f/pop-to-edi
 7951     59/pop-to-ecx
 7952     58/pop-to-eax
 7953     # . epilogue
 7954     89/<- %esp 5/r32/ebp
 7955     5d/pop-to-ebp
 7956     c3/return
 7957 
 7958 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)
 7959     # . prologue
 7960     55/push-ebp
 7961     89/<- %ebp 4/r32/esp
 7962     # . save registers
 7963     50/push-eax
 7964     51/push-ecx
 7965     52/push-edx
 7966     53/push-ebx
 7967     57/push-edi
 7968     # edi = out
 7969     8b/-> *(ebp+0x10) 7/r32/edi
 7970     # var word-slice/ecx: slice
 7971     68/push 0/imm32/end
 7972     68/push 0/imm32/start
 7973     89/<- %ecx 4/r32/esp
 7974     # var v/edx: (handle var)
 7975     68/push 0/imm32
 7976     68/push 0/imm32
 7977     89/<- %edx 4/r32/esp
 7978     # v = parse-var-with-type(next-mu-token(line))
 7979     (next-mu-token *(ebp+8) %ecx)
 7980     (parse-var-with-type %ecx *(ebp+8) %edx *(ebp+0x18) *(ebp+0x1c))
 7981     # var v-addr/eax: (addr var)
 7982     (lookup *edx *(edx+4))  # => eax
 7983     # v->block-depth = *Curr-block-depth
 7984     8b/-> *Curr-block-depth 3/r32/ebx
 7985     89/<- *(eax+0x10) 3/r32/ebx  # Var-block-depth
 7986     # either v has no register and there's no more to this line
 7987     8b/-> *(eax+0x18) 0/r32/eax  # Var-register
 7988     3d/compare-eax-and 0/imm32
 7989     {
 7990       75/jump-if-!= break/disp8
 7991       # TODO: disallow vars of type 'byte' on the stack
 7992       # ensure that there's nothing else on this line
 7993       (next-mu-token *(ebp+8) %ecx)
 7994       (slice-empty? %ecx)  # => eax
 7995       3d/compare-eax-and 0/imm32/false
 7996       0f 84/jump-if-= $parse-mu-var-def:error2/disp32
 7997       #
 7998       (new-var-def Heap  *edx *(edx+4)  %edi)
 7999       e9/jump $parse-mu-var-def:update-vars/disp32
 8000     }
 8001     # or v has a register and there's more to this line
 8002     {
 8003       0f 84/jump-if-= break/disp32
 8004       # TODO: disallow vars of type 'byte' in registers 'esi' or 'edi'
 8005       # TODO: vars of type 'byte' should only be initialized by clearing to 0
 8006       # ensure that the next word is '<-'
 8007       (next-mu-token *(ebp+8) %ecx)
 8008       (slice-equal? %ecx "<-")  # => eax
 8009       3d/compare-eax-and 0/imm32/false
 8010       0f 84/jump-if-= $parse-mu-var-def:error1/disp32
 8011       #
 8012       (new-reg-var-def Heap  *edx *(edx+4)  %edi)
 8013       (lookup *edi *(edi+4))  # => eax
 8014       (add-operation-and-inputs-to-stmt %eax *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 8015     }
 8016 $parse-mu-var-def:update-vars:
 8017     # push 'v' at end of function
 8018     (push *(ebp+0xc) *edx)
 8019     (push *(ebp+0xc) *(edx+4))
 8020     (push *(ebp+0xc) 0)  # Live-var-register-spilled is unused during parsing
 8021 $parse-mu-var-def:end:
 8022     # . reclaim locals
 8023     81 0/subop/add %esp 0x10/imm32
 8024     # . restore registers
 8025     5f/pop-to-edi
 8026     5b/pop-to-ebx
 8027     5a/pop-to-edx
 8028     59/pop-to-ecx
 8029     58/pop-to-eax
 8030     # . epilogue
 8031     89/<- %esp 5/r32/ebp
 8032     5d/pop-to-ebp
 8033     c3/return
 8034 
 8035 $parse-mu-var-def:error1:
 8036     (rewind-stream *(ebp+8))
 8037     # error("register variable requires a valid instruction to initialize but got '" line "'\n")
 8038     (write-buffered *(ebp+0x18) "register variable requires a valid instruction to initialize but got '")
 8039     (flush *(ebp+0x18))
 8040     (write-stream-data *(ebp+0x18) *(ebp+8))
 8041     (write-buffered *(ebp+0x18) "'\n")
 8042     (flush *(ebp+0x18))
 8043     (stop *(ebp+0x1c) 1)
 8044     # never gets here
 8045 
 8046 $parse-mu-var-def:error2:
 8047     (rewind-stream *(ebp+8))
 8048     # error("fn " fn ": var " var ": variables on the stack can't take an initializer\n")
 8049     (write-buffered *(ebp+0x18) "fn ")
 8050     8b/-> *(ebp+0x14) 0/r32/eax
 8051     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 8052     (write-buffered *(ebp+0x18) %eax)
 8053     (write-buffered *(ebp+0x18) ": var ")
 8054     # var v-addr/eax: (addr var) = lookup(v)
 8055     (lookup *edx *(edx+4))  # => eax
 8056     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 8057     (write-buffered *(ebp+0x18) %eax)
 8058     (write-buffered *(ebp+0x18) ": variables on the stack can't take an initializer\n")
 8059     (flush *(ebp+0x18))
 8060     (stop *(ebp+0x1c) 1)
 8061     # never gets here
 8062 
 8063 test-parse-mu-var-def:
 8064     # 'var n: int'
 8065     # . prologue
 8066     55/push-ebp
 8067     89/<- %ebp 4/r32/esp
 8068     # setup
 8069     (clear-stream _test-input-stream)
 8070     (write _test-input-stream "n: int\n")  # caller has consumed the 'var'
 8071     c7 0/subop/copy *Curr-block-depth 1/imm32
 8072     # var out/esi: (handle stmt)
 8073     68/push 0/imm32
 8074     68/push 0/imm32
 8075     89/<- %esi 4/r32/esp
 8076     # var vars/ecx: (stack (addr var) 16)
 8077     81 5/subop/subtract %esp 0xc0/imm32
 8078     68/push 0xc0/imm32/size
 8079     68/push 0/imm32/top
 8080     89/<- %ecx 4/r32/esp
 8081     (clear-stack %ecx)
 8082     # convert
 8083     (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0)
 8084     # var out-addr/esi: (addr stmt)
 8085     (lookup *esi *(esi+4))  # => eax
 8086     89/<- %esi 0/r32/eax
 8087     #
 8088     (check-ints-equal *esi 2 "F - test-parse-mu-var-def/tag")  # Stmt-tag is var-def
 8089     # var v/ecx: (addr var) = lookup(out->var)
 8090     (lookup *(esi+4) *(esi+8))  # Vardef-var Vardef-var => eax
 8091     89/<- %ecx 0/r32/eax
 8092     # v->name
 8093     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 8094     (check-strings-equal %eax "n" "F - test-parse-mu-var-def/var-name")
 8095     # v->register
 8096     (check-ints-equal *(ecx+0x18) 0 "F - test-parse-mu-var-def/var-register")  # Var-register
 8097     # v->block-depth
 8098     (check-ints-equal *(ecx+0x10) 1 "F - test-parse-mu-var-def/output-block-depth")  # Var-block-depth
 8099     # v->type == int
 8100     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 8101     (check-ints-equal *eax 1 "F - test-parse-mu-var-def/var-type:0")  # Tree-is-atom
 8102     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-var-def/var-type:1")  # Tree-value
 8103     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-var-def/var-type:2")  # Tree-right
 8104     # . epilogue
 8105     89/<- %esp 5/r32/ebp
 8106     5d/pop-to-ebp
 8107     c3/return
 8108 
 8109 test-parse-mu-reg-var-def:
 8110     # 'var n/eax: int <- copy 0'
 8111     # . prologue
 8112     55/push-ebp
 8113     89/<- %ebp 4/r32/esp
 8114     # setup
 8115     (clear-stream _test-input-stream)
 8116     (write _test-input-stream "n/eax: int <- copy 0\n")  # caller has consumed the 'var'
 8117     c7 0/subop/copy *Curr-block-depth 1/imm32
 8118     # var out/esi: (handle stmt)
 8119     68/push 0/imm32
 8120     68/push 0/imm32
 8121     89/<- %esi 4/r32/esp
 8122     # var vars/ecx: (stack (addr var) 16)
 8123     81 5/subop/subtract %esp 0xc0/imm32
 8124     68/push 0xc0/imm32/size
 8125     68/push 0/imm32/top
 8126     89/<- %ecx 4/r32/esp
 8127     (clear-stack %ecx)
 8128     # convert
 8129     (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0)
 8130     # var out-addr/esi: (addr stmt)
 8131     (lookup *esi *(esi+4))  # => eax
 8132     89/<- %esi 0/r32/eax
 8133     #
 8134     (check-ints-equal *esi 3 "F - test-parse-mu-reg-var-def/tag")  # Stmt-tag is reg-var-def
 8135     # var v/ecx: (addr var) = lookup(out->outputs->value)
 8136     # . eax: (addr stmt-var) = lookup(out->outputs)
 8137     (lookup *(esi+0x14) *(esi+0x18))  # Regvardef-outputs Regvardef-outputs => eax
 8138     # .
 8139     (check-ints-equal *(eax+8) 0 "F - test-parse-mu-reg-var-def/single-output")  # Stmt-var-next
 8140     # . eax: (addr var) = lookup(eax->value)
 8141     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 8142     # . ecx = eax
 8143     89/<- %ecx 0/r32/eax
 8144     # v->name
 8145     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 8146     (check-strings-equal %eax "n" "F - test-parse-mu-reg-var-def/output-name")  # Var-name
 8147     # v->register
 8148     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 8149     (check-strings-equal %eax "eax" "F - test-parse-mu-reg-var-def/output-register")
 8150     # v->block-depth
 8151     (check-ints-equal *(ecx+0x10) 1 "F - test-parse-mu-reg-var-def/output-block-depth")  # Var-block-depth
 8152     # v->type == int
 8153     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 8154     (check-ints-equal *eax 1 "F - test-parse-mu-reg-var-def/output-type:0")  # Tree-is-atom
 8155     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-reg-var-def/output-type:1")  # Tree-value
 8156     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-reg-var-def/output-type:2")  # Tree-right
 8157     # . epilogue
 8158     89/<- %esp 5/r32/ebp
 8159     5d/pop-to-ebp
 8160     c3/return
 8161 
 8162 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)
 8163     # Carefully push any outputs on the vars stack _after_ reading the inputs
 8164     # that may conflict with them.
 8165     #
 8166     # The only situation in which outputs are pushed here (when it's not a
 8167     # 'var' vardef stmt), and so can possibly conflict with inputs, is if the
 8168     # output is a function output.
 8169     #
 8170     # pseudocode:
 8171     #   var name: slice
 8172     #   allocate(Heap, Stmt-size, out)
 8173     #   var out-addr: (addr stmt) = lookup(*out)
 8174     #   out-addr->tag = stmt
 8175     #   if stmt-has-outputs?(line)
 8176     #     while true
 8177     #       name = next-mu-token(line)
 8178     #       if (name == '<-') break
 8179     #       assert(is-identifier?(name))
 8180     #       var v: (handle var) = lookup-var-or-find-in-fn-outputs(name, vars, fn)
 8181     #       out-addr->outputs = append(v, out-addr->outputs)
 8182     #   add-operation-and-inputs-to-stmt(out-addr, line, vars)
 8183     #   for output in stmt->outputs:
 8184     #     maybe-define-var(output, vars)
 8185     #
 8186     # . prologue
 8187     55/push-ebp
 8188     89/<- %ebp 4/r32/esp
 8189     # . save registers
 8190     50/push-eax
 8191     51/push-ecx
 8192     52/push-edx
 8193     53/push-ebx
 8194     57/push-edi
 8195     # var name/ecx: slice
 8196     68/push 0/imm32/end
 8197     68/push 0/imm32/start
 8198     89/<- %ecx 4/r32/esp
 8199     # var is-deref?/edx: boolean = false
 8200     ba/copy-to-edx 0/imm32/false
 8201     # var v: (handle var)
 8202     68/push 0/imm32
 8203     68/push 0/imm32
 8204     89/<- %ebx 4/r32/esp
 8205     #
 8206     (allocate Heap *Stmt-size *(ebp+0x14))
 8207     # var out-addr/edi: (addr stmt) = lookup(*out)
 8208     8b/-> *(ebp+0x14) 7/r32/edi
 8209     (lookup *edi *(edi+4))  # => eax
 8210     89/<- %edi 0/r32/eax
 8211     # out-addr->tag = 1/stmt
 8212     c7 0/subop/copy *edi 1/imm32/stmt1  # Stmt-tag
 8213     {
 8214       (stmt-has-outputs? *(ebp+8))
 8215       3d/compare-eax-and 0/imm32/false
 8216       0f 84/jump-if-= break/disp32
 8217       {
 8218 $parse-mu-stmt:read-outputs:
 8219         # name = next-mu-token(line)
 8220         (next-mu-token *(ebp+8) %ecx)
 8221         # if slice-empty?(word-slice) break
 8222         (slice-empty? %ecx)  # => eax
 8223         3d/compare-eax-and 0/imm32/false
 8224         0f 85/jump-if-!= break/disp32
 8225         # if (name == "<-") break
 8226         (slice-equal? %ecx "<-")  # => eax
 8227         3d/compare-eax-and 0/imm32/false
 8228         0f 85/jump-if-!= break/disp32
 8229         # is-deref? = false
 8230         ba/copy-to-edx 0/imm32/false
 8231         # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
 8232         8b/-> *ecx 0/r32/eax  # Slice-start
 8233         8a/copy-byte *eax 0/r32/AL
 8234         81 4/subop/and %eax 0xff/imm32
 8235         3d/compare-eax-and 0x2a/imm32/asterisk
 8236         {
 8237           75/jump-if-!= break/disp8
 8238           ff 0/subop/increment *ecx
 8239           ba/copy-to-edx 1/imm32/true
 8240         }
 8241         # assert(is-identifier?(name))
 8242         (is-identifier? %ecx)  # => eax
 8243         3d/compare-eax-and 0/imm32/false
 8244         0f 84/jump-if-= $parse-mu-stmt:abort/disp32
 8245         #
 8246         (lookup-var-or-find-in-fn-outputs %ecx *(ebp+0xc) *(ebp+0x10) %ebx *(ebp+0x18) *(ebp+0x1c))
 8247         8d/copy-address *(edi+0x14) 0/r32/eax  # Stmt1-outputs
 8248         (append-stmt-var Heap  *ebx *(ebx+4)  *(edi+0x14) *(edi+0x18)  %edx  %eax)  # Stmt1-outputs
 8249         #
 8250         e9/jump loop/disp32
 8251       }
 8252     }
 8253     (add-operation-and-inputs-to-stmt %edi *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
 8254 $parse-mu-stmt:define-outputs:
 8255     # var output/edi: (addr stmt-var) = lookup(out-addr->outputs)
 8256     (lookup *(edi+0x14) *(edi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
 8257     89/<- %edi 0/r32/eax
 8258     {
 8259 $parse-mu-stmt:define-outputs-loop:
 8260       # if (output == null) break
 8261       81 7/subop/compare %edi 0/imm32
 8262       74/jump-if-= break/disp8
 8263       #
 8264       (maybe-define-var *edi *(edi+4)  *(ebp+0xc))  # if output is a deref, then it's already been defined,
 8265                                                     # and must be in vars. This call will be a no-op, but safe.
 8266       # output = output->next
 8267       (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
 8268       89/<- %edi 0/r32/eax
 8269       #
 8270       eb/jump loop/disp8
 8271     }
 8272 $parse-mu-stmt:end:
 8273     # . reclaim locals
 8274     81 0/subop/add %esp 0x10/imm32
 8275     # . restore registers
 8276     5f/pop-to-edi
 8277     5b/pop-to-ebx
 8278     5a/pop-to-edx
 8279     59/pop-to-ecx
 8280     58/pop-to-eax
 8281     # . epilogue
 8282     89/<- %esp 5/r32/ebp
 8283     5d/pop-to-ebp
 8284     c3/return
 8285 
 8286 $parse-mu-stmt:abort:
 8287     # error("invalid identifier '" name "'\n")
 8288     (write-buffered *(ebp+0x18) "invalid identifier '")
 8289     (write-slice-buffered *(ebp+0x18) %ecx)
 8290     (write-buffered *(ebp+0x18) "'\n")
 8291     (flush *(ebp+0x18))
 8292     (stop *(ebp+0x1c) 1)
 8293     # never gets here
 8294 
 8295 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)
 8296     # pseudocode:
 8297     #   stmt->name = slice-to-string(next-mu-token(line))
 8298     #   while true
 8299     #     name = next-mu-token(line)
 8300     #     v = lookup-var-or-literal(name)
 8301     #     stmt->inouts = append(v, stmt->inouts)
 8302     #
 8303     # . prologue
 8304     55/push-ebp
 8305     89/<- %ebp 4/r32/esp
 8306     # . save registers
 8307     50/push-eax
 8308     51/push-ecx
 8309     52/push-edx
 8310     53/push-ebx
 8311     56/push-esi
 8312     57/push-edi
 8313     # edi = stmt
 8314     8b/-> *(ebp+8) 7/r32/edi
 8315     # var name/ecx: slice
 8316     68/push 0/imm32/end
 8317     68/push 0/imm32/start
 8318     89/<- %ecx 4/r32/esp
 8319     # var is-deref?/edx: boolean = false
 8320     ba/copy-to-edx 0/imm32/false
 8321     # var v/esi: (handle var)
 8322     68/push 0/imm32
 8323     68/push 0/imm32
 8324     89/<- %esi 4/r32/esp
 8325 $add-operation-and-inputs-to-stmt:read-operation:
 8326     (next-mu-token *(ebp+0xc) %ecx)
 8327     8d/copy-address *(edi+4) 0/r32/eax  # Stmt1-operation or Regvardef-operationStmt1-operation or Regvardef-operation
 8328     (slice-to-string Heap %ecx %eax)
 8329     # var is-get?/ebx: boolean = (name == "get")
 8330     (slice-equal? %ecx "get")  # => eax
 8331     89/<- %ebx 0/r32/eax
 8332     {
 8333 $add-operation-and-inputs-to-stmt:read-inouts:
 8334       # name = next-mu-token(line)
 8335       (next-mu-token *(ebp+0xc) %ecx)
 8336       # if slice-empty?(word-slice) break
 8337       (slice-empty? %ecx)  # => eax
 8338       3d/compare-eax-and 0/imm32/false
 8339       0f 85/jump-if-!= break/disp32
 8340       # if (name == "<-") abort
 8341       (slice-equal? %ecx "<-")
 8342       3d/compare-eax-and 0/imm32/false
 8343       0f 85/jump-if-!= $add-operation-and-inputs-to-stmt:abort/disp32
 8344       # if (is-get? && second operand) lookup or create offset
 8345       {
 8346         81 7/subop/compare %ebx 0/imm32/false
 8347         74/jump-if-= break/disp8
 8348         (lookup *(edi+0xc) *(edi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 8349         3d/compare-eax-and 0/imm32
 8350         74/jump-if-= break/disp8
 8351         (lookup-or-create-constant %eax %ecx %esi)
 8352 #?         (lookup *esi *(esi+4))
 8353 #?         (write-buffered Stderr "creating new output var ")
 8354 #?         (write-int32-hex-buffered Stderr %eax)
 8355 #?         (write-buffered Stderr " for field called ")
 8356 #?         (write-slice-buffered Stderr %ecx)
 8357 #?         (write-buffered Stderr "; var name ")
 8358 #?         (lookup *eax *(eax+4))  # Var-name
 8359 #?         (write-buffered Stderr %eax)
 8360 #?         (write-buffered Stderr Newline)
 8361 #?         (flush Stderr)
 8362         e9/jump $add-operation-and-inputs-to-stmt:save-var/disp32
 8363       }
 8364       # is-deref? = false
 8365       ba/copy-to-edx 0/imm32/false
 8366       # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
 8367       8b/-> *ecx 0/r32/eax  # Slice-start
 8368       8a/copy-byte *eax 0/r32/AL
 8369       81 4/subop/and %eax 0xff/imm32
 8370       3d/compare-eax-and 0x2a/imm32/asterisk
 8371       {
 8372         75/jump-if-!= break/disp8
 8373 $add-operation-and-inputs-to-stmt:inout-is-deref:
 8374         ff 0/subop/increment *ecx
 8375         ba/copy-to-edx 1/imm32/true
 8376       }
 8377       (lookup-var-or-literal %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 8378 $add-operation-and-inputs-to-stmt:save-var:
 8379       8d/copy-address *(edi+0xc) 0/r32/eax
 8380       (append-stmt-var Heap  *esi *(esi+4)  *(edi+0xc) *(edi+0x10)  %edx  %eax)  # Stmt1-inouts or Regvardef-inouts
 8381       #
 8382       e9/jump loop/disp32
 8383     }
 8384 $add-operation-and-inputs-to-stmt:end:
 8385     # . reclaim locals
 8386     81 0/subop/add %esp 0x10/imm32
 8387     # . restore registers
 8388     5f/pop-to-edi
 8389     5e/pop-to-esi
 8390     5b/pop-to-ebx
 8391     5a/pop-to-edx
 8392     59/pop-to-ecx
 8393     58/pop-to-eax
 8394     # . epilogue
 8395     89/<- %esp 5/r32/ebp
 8396     5d/pop-to-ebp
 8397     c3/return
 8398 
 8399 $add-operation-and-inputs-to-stmt:abort:
 8400     # error("fn ___: invalid identifier in '" line "'\n")
 8401     (write-buffered *(ebp+0x18) "fn ")
 8402     8b/-> *(ebp+0x14) 0/r32/eax
 8403     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 8404     (write-buffered *(ebp+0x18) %eax)
 8405     (rewind-stream *(ebp+0xc))
 8406     (write-buffered *(ebp+0x18) ": invalid identifier in '")
 8407     (write-stream-data *(ebp+0x18) *(ebp+0xc))
 8408     (write-buffered *(ebp+0x18) "'\n")
 8409     (flush *(ebp+0x18))
 8410     (stop *(ebp+0x1c) 1)
 8411     # never gets here
 8412 
 8413 stmt-has-outputs?:  # line: (addr stream byte) -> result/eax: boolean
 8414     # . prologue
 8415     55/push-ebp
 8416     89/<- %ebp 4/r32/esp
 8417     # . save registers
 8418     51/push-ecx
 8419     # var word-slice/ecx: slice
 8420     68/push 0/imm32/end
 8421     68/push 0/imm32/start
 8422     89/<- %ecx 4/r32/esp
 8423     # result = false
 8424     b8/copy-to-eax 0/imm32/false
 8425     (rewind-stream *(ebp+8))
 8426     {
 8427       (next-mu-token *(ebp+8) %ecx)
 8428       # if slice-empty?(word-slice) break
 8429       (slice-empty? %ecx)
 8430       3d/compare-eax-and 0/imm32/false
 8431       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
 8432       0f 85/jump-if-!= break/disp32
 8433       # if slice-starts-with?(word-slice, '#') break
 8434       # . eax = *word-slice->start
 8435       8b/-> *ecx 0/r32/eax
 8436       8a/copy-byte *eax 0/r32/AL
 8437       81 4/subop/and %eax 0xff/imm32
 8438       # . if (eax == '#') break
 8439       3d/compare-eax-and 0x23/imm32/hash
 8440       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
 8441       0f 84/jump-if-= break/disp32
 8442       # if slice-equal?(word-slice, '<-') return true
 8443       (slice-equal? %ecx "<-")
 8444       3d/compare-eax-and 0/imm32/false
 8445       74/jump-if-= loop/disp8
 8446       b8/copy-to-eax 1/imm32/true
 8447     }
 8448 $stmt-has-outputs:end:
 8449     (rewind-stream *(ebp+8))
 8450     # . reclaim locals
 8451     81 0/subop/add %esp 8/imm32
 8452     # . restore registers
 8453     59/pop-to-ecx
 8454     # . epilogue
 8455     89/<- %esp 5/r32/ebp
 8456     5d/pop-to-ebp
 8457     c3/return
 8458 
 8459 # if 'name' starts with a digit, create a new literal var for it
 8460 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found
 8461 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)
 8462     # . prologue
 8463     55/push-ebp
 8464     89/<- %ebp 4/r32/esp
 8465     # . save registers
 8466     50/push-eax
 8467     51/push-ecx
 8468     56/push-esi
 8469     # esi = name
 8470     8b/-> *(ebp+8) 6/r32/esi
 8471     # if slice-empty?(name) abort
 8472     (slice-empty? %esi)  # => eax
 8473     3d/compare-eax-and 0/imm32/false
 8474     0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32
 8475     # var c/ecx: byte = *name->start
 8476     8b/-> *esi 1/r32/ecx
 8477     8a/copy-byte *ecx 1/r32/CL
 8478     81 4/subop/and %ecx 0xff/imm32
 8479     # if is-decimal-digit?(c) return new var(name)
 8480     {
 8481       (is-decimal-digit? %ecx)  # => eax
 8482       3d/compare-eax-and 0/imm32/false
 8483       74/jump-if-= break/disp8
 8484 $lookup-var-or-literal:literal:
 8485       (new-literal-integer Heap %esi *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
 8486       eb/jump $lookup-var-or-literal:end/disp8
 8487     }
 8488     # else if (c == '"') return new var(name)
 8489     {
 8490       81 7/subop/compare %ecx 0x22/imm32/dquote
 8491       75/jump-if-!= break/disp8
 8492 $lookup-var-or-literal:literal-string:
 8493       (new-literal Heap %esi *(ebp+0x10))
 8494       eb/jump $lookup-var-or-literal:end/disp8
 8495     }
 8496     # otherwise return lookup-var(name, vars)
 8497     {
 8498 $lookup-var-or-literal:var:
 8499       (lookup-var %esi *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 8500     }
 8501 $lookup-var-or-literal:end:
 8502     # . restore registers
 8503     5e/pop-to-esi
 8504     59/pop-to-ecx
 8505     58/pop-to-eax
 8506     # . epilogue
 8507     89/<- %esp 5/r32/ebp
 8508     5d/pop-to-ebp
 8509     c3/return
 8510 
 8511 $lookup-var-or-literal:abort:
 8512     (write-buffered *(ebp+0x18) "fn ")
 8513     8b/-> *(ebp+0x14) 0/r32/eax
 8514     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 8515     (write-buffered *(ebp+0x18) %eax)
 8516     (write-buffered *(ebp+0x18) ": empty variable!")
 8517     (flush *(ebp+0x18))
 8518     (stop *(ebp+0x1c) 1)
 8519     # never gets here
 8520 
 8521 # return first 'name' from the top (back) of 'vars' and abort if not found
 8522 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)
 8523     # . prologue
 8524     55/push-ebp
 8525     89/<- %ebp 4/r32/esp
 8526     # . save registers
 8527     50/push-eax
 8528     #
 8529     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 8530     # if (*out == 0) abort
 8531     8b/-> *(ebp+0x10) 0/r32/eax
 8532     81 7/subop/compare *eax 0/imm32
 8533     74/jump-if-= $lookup-var:abort/disp8
 8534 $lookup-var:end:
 8535     # . restore registers
 8536     58/pop-to-eax
 8537     # . epilogue
 8538     89/<- %esp 5/r32/ebp
 8539     5d/pop-to-ebp
 8540     c3/return
 8541 
 8542 $lookup-var:abort:
 8543     (write-buffered *(ebp+0x18) "fn ")
 8544     8b/-> *(ebp+0x14) 0/r32/eax
 8545     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 8546     (write-buffered *(ebp+0x18) %eax)
 8547     (write-buffered *(ebp+0x18) ": unknown variable '")
 8548     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 8549     (write-buffered *(ebp+0x18) "'\n")
 8550     (flush *(ebp+0x18))
 8551     (stop *(ebp+0x1c) 1)
 8552     # never gets here
 8553 
 8554 # return first 'name' from the top (back) of 'vars', and 0/null if not found
 8555 # ensure that 'name' if in a register is the topmost variable in that register
 8556 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)
 8557     # pseudocode:
 8558     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
 8559     #   var min = vars->data
 8560     #   while curr >= min
 8561     #     var v: (handle var) = *curr
 8562     #     if v->name == name
 8563     #       return
 8564     #     curr -= 12
 8565     #
 8566     # . prologue
 8567     55/push-ebp
 8568     89/<- %ebp 4/r32/esp
 8569     # . save registers
 8570     50/push-eax
 8571     51/push-ecx
 8572     52/push-edx
 8573     53/push-ebx
 8574     56/push-esi
 8575     57/push-edi
 8576     # clear out
 8577     (zero-out *(ebp+0x10) *Handle-size)
 8578     # esi = vars
 8579     8b/-> *(ebp+0xc) 6/r32/esi
 8580     # ebx = vars->top
 8581     8b/-> *esi 3/r32/ebx
 8582     # if (vars->top > vars->size) abort
 8583     3b/compare<- *(esi+4) 0/r32/eax
 8584     0f 8f/jump-if-> $lookup-var-helper:error1/disp32
 8585     # var min/edx: (addr handle var) = vars->data
 8586     8d/copy-address *(esi+8) 2/r32/edx
 8587     # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
 8588     8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
 8589     # var var-in-reg/edi: 8 addrs
 8590     68/push 0/imm32
 8591     68/push 0/imm32
 8592     68/push 0/imm32
 8593     68/push 0/imm32
 8594     68/push 0/imm32
 8595     68/push 0/imm32
 8596     68/push 0/imm32
 8597     68/push 0/imm32
 8598     89/<- %edi 4/r32/esp
 8599     {
 8600 $lookup-var-helper:loop:
 8601       # if (curr < min) return
 8602       39/compare %ebx 2/r32/edx
 8603       0f 82/jump-if-addr< break/disp32
 8604       # var v/ecx: (addr var) = lookup(*curr)
 8605       (lookup *ebx *(ebx+4))  # => eax
 8606       89/<- %ecx 0/r32/eax
 8607       # var vn/eax: (addr array byte) = lookup(v->name)
 8608       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 8609       # if (vn == name) return curr
 8610       (slice-equal? *(ebp+8) %eax)  # => eax
 8611       3d/compare-eax-and 0/imm32/false
 8612       {
 8613         74/jump-if-= break/disp8
 8614 $lookup-var-helper:found:
 8615         # var vr/eax: (addr array byte) = lookup(v->register)
 8616         (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 8617         3d/compare-eax-and 0/imm32
 8618         {
 8619           74/jump-if-= break/disp8
 8620 $lookup-var-helper:found-register:
 8621           # var reg/eax: int = get(Registers, vr)
 8622           (get Mu-registers %eax 0xc "Mu-registers")  # => eax
 8623           8b/-> *eax 0/r32/eax
 8624           # if (var-in-reg[reg]) error
 8625           8b/-> *(edi+eax<<2) 0/r32/eax
 8626           3d/compare-eax-and 0/imm32
 8627           0f 85/jump-if-!= $lookup-var-helper:error2/disp32
 8628         }
 8629 $lookup-var-helper:return:
 8630         # esi = out
 8631         8b/-> *(ebp+0x10) 6/r32/esi
 8632         # *out = *curr
 8633         8b/-> *ebx 0/r32/eax
 8634         89/<- *esi 0/r32/eax
 8635         8b/-> *(ebx+4) 0/r32/eax
 8636         89/<- *(esi+4) 0/r32/eax
 8637         # return
 8638         eb/jump $lookup-var-helper:end/disp8
 8639       }
 8640       # 'name' not yet found; update var-in-reg if v in register
 8641       # . var vr/eax: (addr array byte) = lookup(v->register)
 8642       (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 8643       # . if (var == 0) continue
 8644       3d/compare-eax-and 0/imm32
 8645       74/jump-if-= $lookup-var-helper:continue/disp8
 8646       # . var reg/eax: int = get(Registers, vr)
 8647       (get Mu-registers %eax 0xc "Mu-registers")  # => eax
 8648       8b/-> *eax 0/r32/eax
 8649       # . if (var-in-reg[reg] == 0) var-in-reg[reg] = v
 8650       81 7/subop/compare *(edi+eax<<2) 0/imm32
 8651       75/jump-if-!= $lookup-var-helper:continue/disp8
 8652       89/<- *(edi+eax<<2) 1/r32/ecx
 8653 $lookup-var-helper:continue:
 8654       # curr -= 12
 8655       81 5/subop/subtract %ebx 0xc/imm32
 8656       e9/jump loop/disp32
 8657     }
 8658 $lookup-var-helper:end:
 8659     # . reclaim locals
 8660     81 0/subop/add %esp 0x20/imm32
 8661     # . restore registers
 8662     5f/pop-to-edi
 8663     5e/pop-to-esi
 8664     5b/pop-to-ebx
 8665     5a/pop-to-edx
 8666     59/pop-to-ecx
 8667     58/pop-to-eax
 8668     # . epilogue
 8669     89/<- %esp 5/r32/ebp
 8670     5d/pop-to-ebp
 8671     c3/return
 8672 
 8673 $lookup-var-helper:error1:
 8674     (write-buffered *(ebp+0x18) "fn ")
 8675     8b/-> *(ebp+0x14) 0/r32/eax
 8676     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 8677     (write-buffered *(ebp+0x18) %eax)
 8678     (write-buffered *(ebp+0x18) ": malformed stack when looking up '")
 8679     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 8680     (write-buffered *(ebp+0x18) "'\n")
 8681     (flush *(ebp+0x18))
 8682     (stop *(ebp+0x1c) 1)
 8683     # never gets here
 8684 
 8685 $lookup-var-helper:error2:
 8686     # eax contains the conflicting var at this point
 8687     (write-buffered *(ebp+0x18) "fn ")
 8688     50/push-eax
 8689     8b/-> *(ebp+0x14) 0/r32/eax
 8690     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 8691     (write-buffered *(ebp+0x18) %eax)
 8692     58/pop-eax
 8693     (write-buffered *(ebp+0x18) ": register ")
 8694     50/push-eax
 8695     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
 8696     (write-buffered *(ebp+0x18) %eax)
 8697     58/pop-to-eax
 8698     (write-buffered *(ebp+0x18) " reads var '")
 8699     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 8700     (write-buffered *(ebp+0x18) "' after writing var '")
 8701     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 8702     (write-buffered *(ebp+0x18) %eax)
 8703     (write-buffered *(ebp+0x18) "'\n")
 8704     (flush *(ebp+0x18))
 8705     (stop *(ebp+0x1c) 1)
 8706     # never gets here
 8707 
 8708 dump-vars:  # vars: (addr stack live-var)
 8709     # pseudocode:
 8710     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
 8711     #   var min = vars->data
 8712     #   while curr >= min
 8713     #     var v: (handle var) = *curr
 8714     #     print v
 8715     #     curr -= 12
 8716     #
 8717     # . prologue
 8718     55/push-ebp
 8719     89/<- %ebp 4/r32/esp
 8720     # . save registers
 8721     52/push-edx
 8722     53/push-ebx
 8723     56/push-esi
 8724     # esi = vars
 8725     8b/-> *(ebp+8) 6/r32/esi
 8726     # ebx = vars->top
 8727     8b/-> *esi 3/r32/ebx
 8728     # var min/edx: (addr handle var) = vars->data
 8729     8d/copy-address *(esi+8) 2/r32/edx
 8730     # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
 8731     8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
 8732     {
 8733 $dump-vars:loop:
 8734       # if (curr < min) return
 8735       39/compare %ebx 2/r32/edx
 8736       0f 82/jump-if-addr< break/disp32
 8737       #
 8738       (write-buffered Stderr "  var@")
 8739       (dump-var 2 %ebx)
 8740       # curr -= 12
 8741       81 5/subop/subtract %ebx 0xc/imm32
 8742       e9/jump loop/disp32
 8743     }
 8744 $dump-vars:end:
 8745     # . restore registers
 8746     5e/pop-to-esi
 8747     5b/pop-to-ebx
 8748     5a/pop-to-edx
 8749     # . epilogue
 8750     89/<- %esp 5/r32/ebp
 8751     5d/pop-to-ebp
 8752     c3/return
 8753 
 8754 == data
 8755 # Like Registers, but no esp or ebp
 8756 Mu-registers:  # (addr stream {(handle array byte), int})
 8757   # a table is a stream
 8758   0x48/imm32/write
 8759   0/imm32/read
 8760   0x48/imm32/length
 8761   # data
 8762   # it is perfectly ok to use fake alloc-ids -- as long as you never try to reclaim them
 8763   0x11/imm32/alloc-id $Mu-register-eax/imm32 0/imm32
 8764   0x11/imm32/alloc-id $Mu-register-ecx/imm32 1/imm32
 8765   0x11/imm32/alloc-id $Mu-register-edx/imm32 2/imm32
 8766   0x11/imm32/alloc-id $Mu-register-ebx/imm32 3/imm32
 8767   0x11/imm32/alloc-id $Mu-register-esi/imm32 6/imm32
 8768   0x11/imm32/alloc-id $Mu-register-edi/imm32 7/imm32
 8769 
 8770 $Mu-register-eax:
 8771   0x11/imm32/alloc-id
 8772   3/imm32/size
 8773   0x65/e 0x61/a 0x78/x
 8774 
 8775 $Mu-register-ecx:
 8776   0x11/imm32/alloc-id
 8777   3/imm32/size
 8778   0x65/e 0x63/c 0x78/x
 8779 
 8780 $Mu-register-edx:
 8781   0x11/imm32/alloc-id
 8782   3/imm32/size
 8783   0x65/e 0x64/d 0x78/x
 8784 
 8785 $Mu-register-ebx:
 8786   0x11/imm32/alloc-id
 8787   3/imm32/size
 8788   0x65/e 0x62/b 0x78/x
 8789 
 8790 $Mu-register-esi:
 8791   0x11/imm32/alloc-id
 8792   3/imm32/size
 8793   0x65/e 0x73/s 0x69/i
 8794 
 8795 $Mu-register-edi:
 8796   0x11/imm32/alloc-id
 8797   3/imm32/size
 8798   0x65/e 0x64/d 0x69/i
 8799 
 8800 == code
 8801 
 8802 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found
 8803 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)
 8804     # . prologue
 8805     55/push-ebp
 8806     89/<- %ebp 4/r32/esp
 8807     # . save registers
 8808     50/push-eax
 8809     #
 8810     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))  # arg order slightly different; 'fn' is deemphasized
 8811     {
 8812       # if (out != 0) return
 8813       8b/-> *(ebp+0x14) 0/r32/eax
 8814       81 7/subop/compare *eax 0/imm32
 8815       75/jump-if-!= break/disp8
 8816       # if name is one of fn's outputs, return it
 8817       (find-in-function-outputs *(ebp+0x10) *(ebp+8) *(ebp+0x14))
 8818       8b/-> *(ebp+0x14) 0/r32/eax
 8819       81 7/subop/compare *eax 0/imm32
 8820       # otherwise abort
 8821       0f 84/jump-if-= $lookup-or-define-var:abort/disp32
 8822     }
 8823 $lookup-or-define-var:end:
 8824     # . restore registers
 8825     58/pop-to-eax
 8826     # . epilogue
 8827     89/<- %esp 5/r32/ebp
 8828     5d/pop-to-ebp
 8829     c3/return
 8830 
 8831 $lookup-or-define-var:abort:
 8832     (write-buffered *(ebp+0x18) "unknown variable '")
 8833     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 8834     (write-buffered *(ebp+0x18) "'\n")
 8835     (flush *(ebp+0x18))
 8836     (stop *(ebp+0x1c) 1)
 8837     # never gets here
 8838 
 8839 find-in-function-outputs:  # fn: (addr function), name: (addr slice), out: (addr handle var)
 8840     # . prologue
 8841     55/push-ebp
 8842     89/<- %ebp 4/r32/esp
 8843     # . save registers
 8844     50/push-eax
 8845     51/push-ecx
 8846     # var curr/ecx: (addr list var) = lookup(fn->outputs)
 8847     8b/-> *(ebp+8) 1/r32/ecx
 8848     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
 8849     89/<- %ecx 0/r32/eax
 8850     # while curr != null
 8851     {
 8852       81 7/subop/compare %ecx 0/imm32
 8853       74/jump-if-= break/disp8
 8854       # var v/eax: (addr var) = lookup(curr->value)
 8855       (lookup *ecx *(ecx+4))  # List-value List-value => eax
 8856       # var s/eax: (addr array byte) = lookup(v->name)
 8857       (lookup *eax *(eax+4))  # Var-name Var-name => eax
 8858       # if (s == name) return curr->value
 8859       (slice-equal? *(ebp+0xc) %eax)  # => eax
 8860       3d/compare-eax-and 0/imm32/false
 8861       {
 8862         74/jump-if-= break/disp8
 8863         # var edi = out
 8864         57/push-edi
 8865         8b/-> *(ebp+0x10) 7/r32/edi
 8866         # *out = curr->value
 8867         8b/-> *ecx 0/r32/eax
 8868         89/<- *edi 0/r32/eax
 8869         8b/-> *(ecx+4) 0/r32/eax
 8870         89/<- *(edi+4) 0/r32/eax
 8871         #
 8872         5f/pop-to-edi
 8873         eb/jump $find-in-function-outputs:end/disp8
 8874       }
 8875       # curr = curr->next
 8876       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
 8877       89/<- %ecx 0/r32/eax
 8878       #
 8879       eb/jump loop/disp8
 8880     }
 8881     b8/copy-to-eax 0/imm32
 8882 $find-in-function-outputs:end:
 8883     # . restore registers
 8884     59/pop-to-ecx
 8885     58/pop-to-eax
 8886     # . epilogue
 8887     89/<- %esp 5/r32/ebp
 8888     5d/pop-to-ebp
 8889     c3/return
 8890 
 8891 # push 'out' to 'vars' if not already there; it's assumed to be a fn output
 8892 maybe-define-var:  # out: (handle var), vars: (addr stack live-var)
 8893     # . prologue
 8894     55/push-ebp
 8895     89/<- %ebp 4/r32/esp
 8896     # . save registers
 8897     50/push-eax
 8898     # var out-addr/eax: (addr var)
 8899     (lookup *(ebp+8) *(ebp+0xc))  # => eax
 8900     #
 8901     (binding-exists? %eax *(ebp+0x10))  # => eax
 8902     3d/compare-eax-and 0/imm32/false
 8903     75/jump-if-!= $maybe-define-var:end/disp8
 8904     # otherwise update vars
 8905     (push *(ebp+0x10) *(ebp+8))
 8906     (push *(ebp+0x10) *(ebp+0xc))
 8907     (push *(ebp+0x10) 0)  # 'out' is always a fn output; never spill it
 8908 $maybe-define-var:end:
 8909     # . restore registers
 8910     58/pop-to-eax
 8911     # . epilogue
 8912     89/<- %esp 5/r32/ebp
 8913     5d/pop-to-ebp
 8914     c3/return
 8915 
 8916 # simpler version of lookup-var-helper
 8917 binding-exists?:  # target: (addr var), vars: (addr stack live-var) -> result/eax: boolean
 8918     # pseudocode:
 8919     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
 8920     #   var min = vars->data
 8921     #   while curr >= min
 8922     #     var v: (handle var) = *curr
 8923     #     if v->name == target->name
 8924     #       return true
 8925     #     curr -= 12
 8926     #   return false
 8927     #
 8928     # . prologue
 8929     55/push-ebp
 8930     89/<- %ebp 4/r32/esp
 8931     # . save registers
 8932     51/push-ecx
 8933     52/push-edx
 8934     56/push-esi
 8935     # var target-name/ecx: (addr array byte) = lookup(target->name)
 8936     8b/-> *(ebp+8) 0/r32/eax
 8937     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 8938     89/<- %ecx 0/r32/eax
 8939     # esi = vars
 8940     8b/-> *(ebp+0xc) 6/r32/esi
 8941     # eax = vars->top
 8942     8b/-> *esi 0/r32/eax
 8943     # var min/edx: (addr handle var) = vars->data
 8944     8d/copy-address *(esi+8) 2/r32/edx
 8945     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
 8946     8d/copy-address *(esi+eax-4) 6/r32/esi  # vars + 8 + vars->type - 12
 8947     {
 8948 $binding-exists?:loop:
 8949       # if (curr < min) return
 8950       39/compare %esi 2/r32/edx
 8951       0f 82/jump-if-addr< break/disp32
 8952       # var v/eax: (addr var) = lookup(*curr)
 8953       (lookup *esi *(esi+4))  # => eax
 8954       # var vn/eax: (addr array byte) = lookup(v->name)
 8955       (lookup *eax *(eax+4))  # Var-name Var-name => eax
 8956       # if (vn == target-name) return true
 8957       (string-equal? %ecx %eax)  # => eax
 8958       3d/compare-eax-and 0/imm32/false
 8959       75/jump-if-!= $binding-exists?:end/disp8  # eax already contains true
 8960       # curr -= 12
 8961       81 5/subop/subtract %esi 0xc/imm32
 8962       e9/jump loop/disp32
 8963     }
 8964     b8/copy-to-eax 0/imm32/false
 8965 $binding-exists?:end:
 8966     # . restore registers
 8967     5e/pop-to-esi
 8968     5a/pop-to-edx
 8969     59/pop-to-ecx
 8970     # . epilogue
 8971     89/<- %esp 5/r32/ebp
 8972     5d/pop-to-ebp
 8973     c3/return
 8974 
 8975 test-parse-mu-stmt:
 8976     # . prologue
 8977     55/push-ebp
 8978     89/<- %ebp 4/r32/esp
 8979     # setup
 8980     (clear-stream _test-input-stream)
 8981     (write _test-input-stream "increment n\n")
 8982     # var vars/ecx: (stack (addr var) 16)
 8983     81 5/subop/subtract %esp 0xc0/imm32
 8984     68/push 0xc0/imm32/size
 8985     68/push 0/imm32/top
 8986     89/<- %ecx 4/r32/esp
 8987     (clear-stack %ecx)
 8988     # var v/edx: (handle var)
 8989     68/push 0/imm32
 8990     68/push 0/imm32
 8991     89/<- %edx 4/r32/esp
 8992     # var s/eax: (handle array byte)
 8993     68/push 0/imm32
 8994     68/push 0/imm32
 8995     89/<- %eax 4/r32/esp
 8996     # v = new var("n")
 8997     (copy-array Heap "n" %eax)
 8998     (new-var Heap *eax *(eax+4) %edx)
 8999     #
 9000     (push %ecx *edx)
 9001     (push %ecx *(edx+4))
 9002     (push %ecx 0)
 9003     # var out/eax: (handle stmt)
 9004     68/push 0/imm32
 9005     68/push 0/imm32
 9006     89/<- %eax 4/r32/esp
 9007     # convert
 9008     (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
 9009     # var out-addr/edx: (addr stmt) = lookup(*out)
 9010     (lookup *eax *(eax+4))  # => eax
 9011     89/<- %edx 0/r32/eax
 9012     # out->tag
 9013     (check-ints-equal *edx 1 "F - test-parse-mu-stmt/tag")  # Stmt-tag is Stmt1
 9014     # out->operation
 9015     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
 9016     (check-strings-equal %eax "increment" "F - test-parse-mu-stmt/name")  # Stmt1-operation
 9017     # out->inouts->value->name
 9018     # . eax = out->inouts
 9019     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9020     # . eax = out->inouts->value
 9021     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9022     # . eax = out->inouts->value->name
 9023     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9024     # .
 9025     (check-strings-equal %eax "n" "F - test-parse-mu-stmt/inout:0")
 9026     # . epilogue
 9027     89/<- %esp 5/r32/ebp
 9028     5d/pop-to-ebp
 9029     c3/return
 9030 
 9031 test-parse-mu-stmt-with-comma:
 9032     # . prologue
 9033     55/push-ebp
 9034     89/<- %ebp 4/r32/esp
 9035     # setup
 9036     (clear-stream _test-input-stream)
 9037     (write _test-input-stream "copy-to n, 3\n")
 9038     # var vars/ecx: (stack (addr var) 16)
 9039     81 5/subop/subtract %esp 0xc0/imm32
 9040     68/push 0xc0/imm32/size
 9041     68/push 0/imm32/top
 9042     89/<- %ecx 4/r32/esp
 9043     (clear-stack %ecx)
 9044     # var v/edx: (handle var)
 9045     68/push 0/imm32
 9046     68/push 0/imm32
 9047     89/<- %edx 4/r32/esp
 9048     # var s/eax: (handle array byte)
 9049     68/push 0/imm32
 9050     68/push 0/imm32
 9051     89/<- %eax 4/r32/esp
 9052     # v = new var("n")
 9053     (copy-array Heap "n" %eax)
 9054     (new-var Heap *eax *(eax+4) %edx)
 9055     #
 9056     (push %ecx *edx)
 9057     (push %ecx *(edx+4))
 9058     (push %ecx 0)
 9059     # var out/eax: (handle stmt)
 9060     68/push 0/imm32
 9061     68/push 0/imm32
 9062     89/<- %eax 4/r32/esp
 9063     # convert
 9064     (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
 9065     # var out-addr/edx: (addr stmt) = lookup(*out)
 9066     (lookup *eax *(eax+4))  # => eax
 9067     89/<- %edx 0/r32/eax
 9068     # out->tag
 9069     (check-ints-equal *edx 1 "F - test-parse-mu-stmt-with-comma/tag")  # Stmt-tag is Stmt1
 9070     # out->operation
 9071     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
 9072     (check-strings-equal %eax "copy-to" "F - test-parse-mu-stmt-with-comma/name")  # Stmt1-operation
 9073     # out->inouts->value->name
 9074     # . eax = out->inouts
 9075     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9076     # . eax = out->inouts->value
 9077     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9078     # . eax = out->inouts->value->name
 9079     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9080     # .
 9081     (check-strings-equal %eax "n" "F - test-parse-mu-stmt-with-comma/inout:0")
 9082     # . epilogue
 9083     89/<- %esp 5/r32/ebp
 9084     5d/pop-to-ebp
 9085     c3/return
 9086 
 9087 new-var:  # ad: (addr allocation-descriptor), name: (handle array byte), out: (addr handle var)
 9088     # . prologue
 9089     55/push-ebp
 9090     89/<- %ebp 4/r32/esp
 9091     # . save registers
 9092     50/push-eax
 9093     51/push-ecx
 9094     # ecx = out
 9095     8b/-> *(ebp+0x14) 1/r32/ecx
 9096     #
 9097     (allocate *(ebp+8) *Var-size %ecx)
 9098     # var out-addr/eax: (addr var)
 9099     (lookup *ecx *(ecx+4))  # => eax
 9100     # out-addr->name = name
 9101     8b/-> *(ebp+0xc) 1/r32/ecx
 9102     89/<- *eax 1/r32/ecx  # Var-name
 9103     8b/-> *(ebp+0x10) 1/r32/ecx
 9104     89/<- *(eax+4) 1/r32/ecx  # Var-name
 9105 #?     (write-buffered Stderr "var ")
 9106 #?     (lookup *(ebp+0xc) *(ebp+0x10))
 9107 #?     (write-buffered Stderr %eax)
 9108 #?     (write-buffered Stderr " at ")
 9109 #?     8b/-> *(ebp+0x14) 1/r32/ecx
 9110 #?     (lookup *ecx *(ecx+4))  # => eax
 9111 #?     (write-int32-hex-buffered Stderr %eax)
 9112 #?     (write-buffered Stderr Newline)
 9113 #?     (flush Stderr)
 9114 $new-var:end:
 9115     # . restore registers
 9116     59/pop-to-ecx
 9117     58/pop-to-eax
 9118     # . epilogue
 9119     89/<- %esp 5/r32/ebp
 9120     5d/pop-to-ebp
 9121     c3/return
 9122 
 9123 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)
 9124     # . prologue
 9125     55/push-ebp
 9126     89/<- %ebp 4/r32/esp
 9127     # . save registers
 9128     50/push-eax
 9129     51/push-ecx
 9130     # if (!is-hex-int?(name)) abort
 9131     (is-hex-int? *(ebp+0xc))  # => eax
 9132     3d/compare-eax-and 0/imm32/false
 9133     0f 84/jump-if-= $new-literal-integer:abort/disp32
 9134     # out = new var(s)
 9135     (new-var-from-slice *(ebp+8) *(ebp+0xc) *(ebp+0x10))
 9136     # var out-addr/ecx: (addr var) = lookup(*out)
 9137     8b/-> *(ebp+0x10) 0/r32/eax
 9138     (lookup *eax *(eax+4))  # => eax
 9139     89/<- %ecx 0/r32/eax
 9140     # out-addr->block-depth = *Curr-block-depth
 9141     8b/-> *Curr-block-depth 0/r32/eax
 9142     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
 9143     # out-addr->type = new tree()
 9144     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
 9145     (allocate *(ebp+8) *Tree-size %eax)
 9146     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 9147     c7 0/subop/copy *eax 1/imm32/true  # Tree-is-atom
 9148     # nothing else to do; default type is 'literal'
 9149 $new-literal-integer:end:
 9150     # . reclaim locals
 9151     81 0/subop/add %esp 8/imm32
 9152     # . restore registers
 9153     59/pop-to-ecx
 9154     58/pop-to-eax
 9155     # . epilogue
 9156     89/<- %esp 5/r32/ebp
 9157     5d/pop-to-ebp
 9158     c3/return
 9159 
 9160 $new-literal-integer:abort:
 9161     (write-buffered *(ebp+0x18) "fn ")
 9162     8b/-> *(ebp+0x14) 0/r32/eax
 9163     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9164     (write-buffered *(ebp+0x18) %eax)
 9165     (write-buffered *(ebp+0x18) ": variable cannot begin with a digit '")
 9166     (write-slice-buffered *(ebp+0x18) *(ebp+0xc))
 9167     (write-buffered *(ebp+0x18) "'\n")
 9168     (flush *(ebp+0x18))
 9169     (stop *(ebp+0x1c) 1)
 9170     # never gets here
 9171 
 9172 new-literal:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
 9173     # . prologue
 9174     55/push-ebp
 9175     89/<- %ebp 4/r32/esp
 9176     # . save registers
 9177     50/push-eax
 9178     51/push-ecx
 9179     # var s/ecx: (handle array byte)
 9180     68/push 0/imm32
 9181     68/push 0/imm32
 9182     89/<- %ecx 4/r32/esp
 9183     # s = slice-to-string(name)
 9184     (slice-to-string Heap *(ebp+0xc) %ecx)
 9185     # allocate to out
 9186     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
 9187     # var out-addr/ecx: (addr var) = lookup(*out)
 9188     8b/-> *(ebp+0x10) 1/r32/ecx
 9189     (lookup *ecx *(ecx+4))  # => eax
 9190     89/<- %ecx 0/r32/eax
 9191     # out-addr->block-depth = *Curr-block-depth
 9192     8b/-> *Curr-block-depth 0/r32/eax
 9193     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
 9194     # out-addr->type/eax = new type
 9195     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
 9196     (allocate *(ebp+8) *Tree-size %eax)
 9197     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 9198     # nothing else to do; default type is 'literal'
 9199     c7 0/subop/copy *eax 1/imm32/true  # Tree-is-atom
 9200 $new-literal:end:
 9201     # . reclaim locals
 9202     81 0/subop/add %esp 8/imm32
 9203     # . restore registers
 9204     59/pop-to-ecx
 9205     58/pop-to-eax
 9206     # . epilogue
 9207     89/<- %esp 5/r32/ebp
 9208     5d/pop-to-ebp
 9209     c3/return
 9210 
 9211 new-var-from-slice:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
 9212     # . prologue
 9213     55/push-ebp
 9214     89/<- %ebp 4/r32/esp
 9215     # . save registers
 9216     51/push-ecx
 9217     # var tmp/ecx: (handle array byte)
 9218     68/push 0/imm32
 9219     68/push 0/imm32
 9220     89/<- %ecx 4/r32/esp
 9221     # tmp = slice-to-string(name)
 9222     (slice-to-string Heap *(ebp+0xc) %ecx)
 9223     # out = new-var(tmp)
 9224     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
 9225 $new-var-from-slice:end:
 9226     # . reclaim locals
 9227     81 0/subop/add %esp 8/imm32
 9228     # . restore registers
 9229     59/pop-to-ecx
 9230     # . epilogue
 9231     89/<- %esp 5/r32/ebp
 9232     5d/pop-to-ebp
 9233     c3/return
 9234 
 9235 new-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
 9236     # . prologue
 9237     55/push-ebp
 9238     89/<- %ebp 4/r32/esp
 9239     # . save registers
 9240     50/push-eax
 9241     51/push-ecx
 9242     #
 9243     (allocate *(ebp+8) *Stmt-size *(ebp+0x14))
 9244     # var out-addr/eax: (addr stmt) = lookup(*out)
 9245     8b/-> *(ebp+0x14) 0/r32/eax
 9246     (lookup *eax *(eax+4))  # => eax
 9247     # out-addr->tag = stmt
 9248     c7 0/subop/copy *eax 2/imm32/tag/var-on-stack  # Stmt-tag
 9249     # result->var = var
 9250     8b/-> *(ebp+0xc) 1/r32/ecx
 9251     89/<- *(eax+4) 1/r32/ecx  # Vardef-var
 9252     8b/-> *(ebp+0x10) 1/r32/ecx
 9253     89/<- *(eax+8) 1/r32/ecx  # Vardef-var
 9254 $new-var-def:end:
 9255     # . restore registers
 9256     59/pop-to-ecx
 9257     58/pop-to-eax
 9258     # . epilogue
 9259     89/<- %esp 5/r32/ebp
 9260     5d/pop-to-ebp
 9261     c3/return
 9262 
 9263 new-reg-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
 9264     # . prologue
 9265     55/push-ebp
 9266     89/<- %ebp 4/r32/esp
 9267     # . save registers
 9268     50/push-eax
 9269     # eax = out
 9270     8b/-> *(ebp+0x14) 0/r32/eax
 9271     #
 9272     (allocate *(ebp+8) *Stmt-size %eax)
 9273     # var out-addr/eax: (addr stmt) = lookup(*out)
 9274     (lookup *eax *(eax+4))  # => eax
 9275     # set tag
 9276     c7 0/subop/copy *eax 3/imm32/tag/var-in-register  # Stmt-tag
 9277     # set output
 9278     8d/copy-address *(eax+0x14) 0/r32/eax  # Regvardef-outputs
 9279     (append-stmt-var Heap  *(ebp+0xc) *(ebp+0x10)  0 0  0  %eax)
 9280 $new-reg-var-def:end:
 9281     # . restore registers
 9282     58/pop-to-eax
 9283     # . epilogue
 9284     89/<- %esp 5/r32/ebp
 9285     5d/pop-to-ebp
 9286     c3/return
 9287 
 9288 append-list:  # ad: (addr allocation-descriptor), value: (handle _type), list: (handle list _type), out: (addr handle list _type)
 9289     # . prologue
 9290     55/push-ebp
 9291     89/<- %ebp 4/r32/esp
 9292     # . save registers
 9293     50/push-eax
 9294     51/push-ecx
 9295     57/push-edi
 9296     # edi = out
 9297     8b/-> *(ebp+0x1c) 7/r32/edi
 9298     # *out = new list
 9299     (allocate *(ebp+8) *List-size %edi)
 9300     # var out-addr/edi: (addr list _type) = lookup(*out)
 9301     (lookup *edi *(edi+4))  # => eax
 9302     89/<- %edi 0/r32/eax
 9303     # out-addr->value = value
 9304     8b/-> *(ebp+0xc) 0/r32/eax
 9305     89/<- *edi 0/r32/eax  # List-value
 9306     8b/-> *(ebp+0x10) 0/r32/eax
 9307     89/<- *(edi+4) 0/r32/eax  # List-value
 9308     # if (list == null) return
 9309     81 7/subop/compare *(ebp+0x14) 0/imm32
 9310     74/jump-if-= $append-list:end/disp8
 9311     # otherwise append
 9312 $append-list:non-empty-list:
 9313     # var curr/eax: (addr list _type) = lookup(list)
 9314     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
 9315     # while (curr->next != null) curr = curr->next
 9316     {
 9317       81 7/subop/compare *(eax+8) 0/imm32  # List-next
 9318       74/jump-if-= break/disp8
 9319       # curr = lookup(curr->next)
 9320       (lookup *(eax+8) *(eax+0xc))  # List-next, List-next => eax
 9321       #
 9322       eb/jump loop/disp8
 9323     }
 9324     # edi = out
 9325     8b/-> *(ebp+0x1c) 7/r32/edi
 9326     # curr->next = out
 9327     8b/-> *edi 1/r32/ecx
 9328     89/<- *(eax+8) 1/r32/ecx  # List-next
 9329     8b/-> *(edi+4) 1/r32/ecx
 9330     89/<- *(eax+0xc) 1/r32/ecx  # List-next
 9331     # out = list
 9332     8b/-> *(ebp+0x14) 1/r32/ecx
 9333     89/<- *edi 1/r32/ecx
 9334     8b/-> *(ebp+0x18) 1/r32/ecx
 9335     89/<- *(edi+4) 1/r32/ecx
 9336 $append-list:end:
 9337     # . restore registers
 9338     5f/pop-to-edi
 9339     59/pop-to-ecx
 9340     58/pop-to-eax
 9341     # . epilogue
 9342     89/<- %esp 5/r32/ebp
 9343     5d/pop-to-ebp
 9344     c3/return
 9345 
 9346 append-stmt-var:  # ad: (addr allocation-descriptor), v: (handle var), vars: (handle stmt-var), is-deref?: boolean, out: (addr handle stmt-var)
 9347     # . prologue
 9348     55/push-ebp
 9349     89/<- %ebp 4/r32/esp
 9350     # . save registers
 9351     50/push-eax
 9352     51/push-ecx
 9353     57/push-edi
 9354     # edi = out
 9355     8b/-> *(ebp+0x20) 7/r32/edi
 9356     # out = new stmt-var
 9357     (allocate *(ebp+8) *Stmt-var-size %edi)
 9358     # var out-addr/ecx: (addr stmt-var) = lookup(*out)
 9359     (lookup *edi *(edi+4))  # => eax
 9360     89/<- %ecx 0/r32/eax
 9361     # out-addr->value = v
 9362     8b/-> *(ebp+0xc) 0/r32/eax
 9363     89/<- *ecx 0/r32/eax  # Stmt-var-value
 9364     8b/-> *(ebp+0x10) 0/r32/eax
 9365     89/<- *(ecx+4) 0/r32/eax  # Stmt-var-value
 9366     # out-addr->is-deref? = is-deref?
 9367     8b/-> *(ebp+0x1c) 0/r32/eax
 9368     89/<- *(ecx+0x10) 0/r32/eax  # Stmt-var-is-deref
 9369     # if (vars == null) return result
 9370     81 7/subop/compare *(ebp+0x14) 0/imm32/null
 9371     74/jump-if-= $append-stmt-var:end/disp8
 9372     # otherwise append
 9373     # var curr/eax: (addr stmt-var) = lookup(vars)
 9374     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
 9375     # while (curr->next != null) curr = curr->next
 9376     {
 9377       81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
 9378       74/jump-if-= break/disp8
 9379       # curr = lookup(curr->next)
 9380       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next, Stmt-var-next => eax
 9381       #
 9382       eb/jump loop/disp8
 9383     }
 9384     # curr->next = out
 9385     8b/-> *edi 1/r32/ecx
 9386     89/<- *(eax+8) 1/r32/ecx  # Stmt-var-next
 9387     8b/-> *(edi+4) 1/r32/ecx
 9388     89/<- *(eax+0xc) 1/r32/ecx  # Stmt-var-next
 9389     # out = vars
 9390     8b/-> *(ebp+0x14) 1/r32/ecx
 9391     89/<- *edi 1/r32/ecx
 9392     8b/-> *(ebp+0x18) 1/r32/ecx
 9393     89/<- *(edi+4) 1/r32/ecx
 9394 $append-stmt-var:end:
 9395     # . restore registers
 9396     5f/pop-to-edi
 9397     59/pop-to-ecx
 9398     58/pop-to-eax
 9399     # . epilogue
 9400     89/<- %esp 5/r32/ebp
 9401     5d/pop-to-ebp
 9402     c3/return
 9403 
 9404 append-to-block:  # ad: (addr allocation-descriptor), block: (addr block), x: (handle stmt)
 9405     # . prologue
 9406     55/push-ebp
 9407     89/<- %ebp 4/r32/esp
 9408     # . save registers
 9409     50/push-eax
 9410     56/push-esi
 9411     # esi = block
 9412     8b/-> *(ebp+0xc) 6/r32/esi
 9413     # block->stmts = append(x, block->stmts)
 9414     8d/copy-address *(esi+4) 0/r32/eax  # Block-stmts
 9415     (append-list *(ebp+8)  *(ebp+0x10) *(ebp+0x14)  *(esi+4) *(esi+8)  %eax)  # ad, x, x, Block-stmts, Block-stmts
 9416 $append-to-block:end:
 9417     # . restore registers
 9418     5e/pop-to-esi
 9419     58/pop-to-eax
 9420     # . epilogue
 9421     89/<- %esp 5/r32/ebp
 9422     5d/pop-to-ebp
 9423     c3/return
 9424 
 9425 ## Parsing types
 9426 # We need to create metadata on user-defined types, and we need to use this
 9427 # metadata as we parse instructions.
 9428 # However, we also want to allow types to be used before their definitions.
 9429 # This means we can't ever assume any type data structures exist.
 9430 
 9431 lookup-or-create-constant:  # container: (addr stmt-var), field-name: (addr slice), out: (addr handle var)
 9432     # . prologue
 9433     55/push-ebp
 9434     89/<- %ebp 4/r32/esp
 9435     # . save registers
 9436     50/push-eax
 9437     56/push-esi
 9438     # var container-type/esi: type-id
 9439     (container-type *(ebp+8))  # => eax
 9440     89/<- %esi 0/r32/eax
 9441     # var tmp/eax: (handle typeinfo) = find-or-create-typeinfo(container-type)
 9442     68/push 0/imm32
 9443     68/push 0/imm32
 9444     89/<- %eax 4/r32/esp
 9445     (find-or-create-typeinfo %esi %eax)
 9446     # var tmp-addr/eax: (addr typeinfo) = lookup(tmp)
 9447     (lookup *eax *(eax+4))  # => eax
 9448     # result = find-or-create-typeinfo-output-var(typeinfo, field-name)
 9449 #?     (write-buffered Stderr "constant: ")
 9450 #?     (write-slice-buffered Stderr *(ebp+0xc))
 9451 #?     (write-buffered Stderr Newline)
 9452 #?     (flush Stderr)
 9453     (find-or-create-typeinfo-output-var %eax *(ebp+0xc) *(ebp+0x10))
 9454 #?     8b/-> *(ebp+0x10) 0/r32/eax
 9455 #?     (write-buffered Stderr "@")
 9456 #?     (lookup *eax *(eax+4))
 9457 #?     (write-int32-hex-buffered Stderr %eax)
 9458 #?     (lookup *eax *(eax+4))
 9459 #?     (write-buffered Stderr %eax)
 9460 #?     (write-buffered Stderr Newline)
 9461 #?     (flush Stderr)
 9462 #?     (write-buffered Stderr "offset: ")
 9463 #?     8b/-> *(eax+0x14) 0/r32/eax
 9464 #?     (write-int32-hex-buffered Stderr %eax)
 9465 #?     (write-buffered Stderr Newline)
 9466 #?     (flush Stderr)
 9467 $lookup-or-create-constant:end:
 9468     # . reclaim locals
 9469     81 0/subop/add %esp 8/imm32
 9470     # . restore registers
 9471     5e/pop-to-esi
 9472     58/pop-to-eax
 9473     # . epilogue
 9474     89/<- %esp 5/r32/ebp
 9475     5d/pop-to-ebp
 9476     c3/return
 9477 
 9478 # if addr var:
 9479 #   container->var->type->right->left->value
 9480 # otherwise
 9481 #   container->var->type->value
 9482 container-type:  # container: (addr stmt-var) -> result/eax: type-id
 9483     # . prologue
 9484     55/push-ebp
 9485     89/<- %ebp 4/r32/esp
 9486     #
 9487     8b/-> *(ebp+8) 0/r32/eax
 9488     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9489     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
 9490     {
 9491       81 7/subop/compare *(eax+8) 0/imm32  # Tree-right
 9492       74/jump-if-= break/disp8
 9493       (lookup *(eax+0xc) *(eax+0x10))  # Tree-right Tree-right => eax
 9494       (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
 9495     }
 9496     8b/-> *(eax+4) 0/r32/eax  # Tree-value
 9497 $container-type:end:
 9498     # . epilogue
 9499     89/<- %esp 5/r32/ebp
 9500     5d/pop-to-ebp
 9501     c3/return
 9502 
 9503 is-container?:  # t: type-id -> result/eax: boolean
 9504     # . prologue
 9505     55/push-ebp
 9506     89/<- %ebp 4/r32/esp
 9507     #
 9508     8b/-> *(ebp+8) 0/r32/eax
 9509     c1/shift 4/subop/left %eax 2/imm8
 9510     3b/compare 0/r32/eax *Primitive-type-ids
 9511     0f 9d/set-if->= %al
 9512     81 4/subop/and %eax 0xff/imm32
 9513 $is-container?:end:
 9514     # . epilogue
 9515     89/<- %esp 5/r32/ebp
 9516     5d/pop-to-ebp
 9517     c3/return
 9518 
 9519 find-or-create-typeinfo:  # t: type-id, out: (addr handle typeinfo)
 9520     # . prologue
 9521     55/push-ebp
 9522     89/<- %ebp 4/r32/esp
 9523     # . save registers
 9524     50/push-eax
 9525     51/push-ecx
 9526     52/push-edx
 9527     57/push-edi
 9528     # edi = out
 9529     8b/-> *(ebp+0xc) 7/r32/edi
 9530     # var fields/ecx: (handle table (handle array byte) (handle typeinfo-entry))
 9531     68/push 0/imm32
 9532     68/push 0/imm32
 9533     89/<- %ecx 4/r32/esp
 9534     # find-typeinfo(t, out)
 9535     (find-typeinfo *(ebp+8) %edi)
 9536     {
 9537       # if (*out != 0) break
 9538       81 7/subop/compare *edi 0/imm32
 9539       0f 85/jump-if-!= break/disp32
 9540 $find-or-create-typeinfo:create:
 9541       # *out = allocate
 9542       (allocate Heap *Typeinfo-size %edi)
 9543       # var tmp/eax: (addr typeinfo) = lookup(*out)
 9544       (lookup *edi *(edi+4))  # => eax
 9545 #?     (write-buffered Stderr "created typeinfo at ")
 9546 #?     (write-int32-hex-buffered Stderr %eax)
 9547 #?     (write-buffered Stderr " for type-id ")
 9548 #?     (write-int32-hex-buffered Stderr *(ebp+8))
 9549 #?     (write-buffered Stderr Newline)
 9550 #?     (flush Stderr)
 9551       # tmp->id = t
 9552       8b/-> *(ebp+8) 2/r32/edx
 9553       89/<- *eax 2/r32/edx  # Typeinfo-id
 9554       # tmp->fields = new table
 9555       # . fields = new table
 9556       (new-stream Heap 0x40 *Typeinfo-fields-row-size %ecx)
 9557       # . tmp->fields = fields
 9558       8b/-> *ecx 2/r32/edx
 9559       89/<- *(eax+4) 2/r32/edx  # Typeinfo-fields
 9560       8b/-> *(ecx+4) 2/r32/edx
 9561       89/<- *(eax+8) 2/r32/edx  # Typeinfo-fields
 9562       # tmp->next = Program->types
 9563       8b/-> *_Program-types 1/r32/ecx
 9564       89/<- *(eax+0x10) 1/r32/ecx  # Typeinfo-next
 9565       8b/-> *_Program-types->payload 1/r32/ecx
 9566       89/<- *(eax+0x14) 1/r32/ecx  # Typeinfo-next
 9567       # Program->types = out
 9568       8b/-> *edi 1/r32/ecx
 9569       89/<- *_Program-types 1/r32/ecx
 9570       8b/-> *(edi+4) 1/r32/ecx
 9571       89/<- *_Program-types->payload 1/r32/ecx
 9572     }
 9573 $find-or-create-typeinfo:end:
 9574     # . reclaim locals
 9575     81 0/subop/add %esp 8/imm32
 9576     # . restore registers
 9577     5f/pop-to-edi
 9578     5a/pop-to-edx
 9579     59/pop-to-ecx
 9580     58/pop-to-eax
 9581     # . epilogue
 9582     89/<- %esp 5/r32/ebp
 9583     5d/pop-to-ebp
 9584     c3/return
 9585 
 9586 find-typeinfo:  # t: type-id, out: (addr handle typeinfo)
 9587     # . prologue
 9588     55/push-ebp
 9589     89/<- %ebp 4/r32/esp
 9590     # . save registers
 9591     50/push-eax
 9592     51/push-ecx
 9593     52/push-edx
 9594     57/push-edi
 9595     # ecx = t
 9596     8b/-> *(ebp+8) 1/r32/ecx
 9597     # edi = out
 9598     8b/-> *(ebp+0xc) 7/r32/edi
 9599     # *out = Program->types
 9600     8b/-> *_Program-types 0/r32/eax
 9601     89/<- *edi 0/r32/eax
 9602     8b/-> *_Program-types->payload 0/r32/eax
 9603     89/<- *(edi+4) 0/r32/eax
 9604     {
 9605 $find-typeinfo:loop:
 9606       # if (*out == 0) break
 9607       81 7/subop/compare *edi 0/imm32
 9608       74/jump-if-= break/disp8
 9609 $find-typeinfo:check:
 9610       # var tmp/eax: (addr typeinfo) = lookup(*out)
 9611       (lookup *edi *(edi+4))  # => eax
 9612       # if (tmp->id == t) break
 9613       39/compare *eax 1/r32/ecx  # Typeinfo-id
 9614       74/jump-if-= break/disp8
 9615 $find-typeinfo:continue:
 9616       # *out = tmp->next
 9617       8b/-> *(eax+0x10) 2/r32/edx  # Typeinfo-next
 9618       89/<- *edi 2/r32/edx
 9619       8b/-> *(eax+0x14) 2/r32/edx  # Typeinfo-next
 9620       89/<- *(edi+4) 2/r32/edx
 9621       #
 9622       eb/jump loop/disp8
 9623     }
 9624 $find-typeinfo:end:
 9625     # . restore registers
 9626     5f/pop-to-edi
 9627     5a/pop-to-edx
 9628     59/pop-to-ecx
 9629     58/pop-to-eax
 9630     # . epilogue
 9631     89/<- %esp 5/r32/ebp
 9632     5d/pop-to-ebp
 9633     c3/return
 9634 
 9635 find-or-create-typeinfo-output-var:  # T: (addr typeinfo), f: (addr slice), out: (addr handle var)
 9636     # . prologue
 9637     55/push-ebp
 9638     89/<- %ebp 4/r32/esp
 9639     # . save registers
 9640     50/push-eax
 9641     52/push-edx
 9642     57/push-edi
 9643     # var dest/edi: (handle typeinfo-entry)
 9644     68/push 0/imm32
 9645     68/push 0/imm32
 9646     89/<- %edi 4/r32/esp
 9647     # find-or-create-typeinfo-fields(T, f, dest)
 9648     (find-or-create-typeinfo-fields *(ebp+8) *(ebp+0xc) %edi)
 9649     # var dest-addr/edi: (addr typeinfo-entry) = lookup(dest)
 9650     (lookup *edi *(edi+4))  # => eax
 9651     89/<- %edi 0/r32/eax
 9652     # if dest-addr->output-var doesn't exist, create it
 9653     {
 9654       81 7/subop/compare *(edi+0xc) 0/imm32  # Typeinfo-entry-output-var
 9655       0f 85/jump-if-!= break/disp32
 9656       # dest-addr->output-var = new var(dummy name, type, -1 offset)
 9657       # . var name/eax: (handle array byte) = "field"
 9658       68/push 0/imm32
 9659       68/push 0/imm32
 9660       89/<- %eax 4/r32/esp
 9661       (slice-to-string Heap *(ebp+0xc) %eax)
 9662       # . new var
 9663       8d/copy-address *(edi+0xc) 2/r32/edx
 9664       (new-var Heap  *eax *(eax+4)  %edx)
 9665       # . reclaim name
 9666       81 0/subop/add %esp 8/imm32
 9667       # var result/edx: (addr var) = lookup(dest-addr->output-var)
 9668       (lookup *(edi+0xc) *(edi+0x10))  # => eax
 9669       89/<- %edx 0/r32/eax
 9670       # result->type = new constant type
 9671       8d/copy-address *(edx+8) 0/r32/eax  # Var-type
 9672       (allocate Heap *Tree-size %eax)
 9673       (lookup *(edx+8) *(edx+0xc))  # => eax
 9674       c7 0/subop/copy *eax 1/imm32/true  # Tree-is-atom
 9675       c7 0/subop/copy *(eax+4) 6/imm32/constant  # Tree-value
 9676       c7 0/subop/copy *(eax+8) 0/imm32  # Tree-left
 9677       c7 0/subop/copy *(eax+0xc) 0/imm32  # Tree-right
 9678       c7 0/subop/copy *(eax+0x10) 0/imm32  # Tree-right
 9679       # result->offset isn't filled out yet
 9680       c7 0/subop/copy *(edx+0x14) -1/imm32/uninitialized  # Var-offset
 9681     }
 9682     # out = dest-addr->output-var
 9683     8b/-> *(ebp+0x10) 2/r32/edx
 9684     8b/-> *(edi+0xc) 0/r32/eax  # Typeinfo-entry-output-var
 9685     89/<- *edx 0/r32/eax
 9686     8b/-> *(edi+0x10) 0/r32/eax  # Typeinfo-entry-output-var
 9687     89/<- *(edx+4) 0/r32/eax
 9688 $find-or-create-typeinfo-output-var:end:
 9689     # . reclaim locals
 9690     81 0/subop/add %esp 8/imm32
 9691     # . restore registers
 9692     5f/pop-to-edi
 9693     5a/pop-to-edx
 9694     58/pop-to-eax
 9695     # . epilogue
 9696     89/<- %esp 5/r32/ebp
 9697     5d/pop-to-ebp
 9698     c3/return
 9699 
 9700 find-or-create-typeinfo-fields:  # T: (addr typeinfo), f: (addr slice), out: (addr handle typeinfo-entry)
 9701     # . prologue
 9702     55/push-ebp
 9703     89/<- %ebp 4/r32/esp
 9704     # . save registers
 9705     50/push-eax
 9706     56/push-esi
 9707     57/push-edi
 9708     # eax = lookup(T->fields)
 9709     8b/-> *(ebp+8) 0/r32/eax
 9710     (lookup *(eax+4) *(eax+8))  # Typeinfo-fields Typeinfo-fields => eax
 9711     # edi = out
 9712     8b/-> *(ebp+0x10) 7/r32/edi
 9713     # var src/esi: (addr handle typeinfo-entry) = get-or-insert-slice(T->fields, f)
 9714     (get-or-insert-slice %eax *(ebp+0xc) *Typeinfo-fields-row-size Heap)  # => eax
 9715     89/<- %esi 0/r32/eax
 9716     # if src doesn't exist, allocate it
 9717     {
 9718       81 7/subop/compare *esi 0/imm32
 9719       75/jump-if-!= break/disp8
 9720       (allocate Heap *Typeinfo-entry-size %esi)
 9721 #?       (write-buffered Stderr "handle at ")
 9722 #?       (write-int32-hex-buffered Stderr %esi)
 9723 #?       (write-buffered Stderr ": ")
 9724 #?       (write-int32-hex-buffered Stderr *esi)
 9725 #?       (write-buffered Stderr " ")
 9726 #?       (write-int32-hex-buffered Stderr *(esi+4))
 9727 #?       (write-buffered Stderr Newline)
 9728 #?       (flush Stderr)
 9729 #?       (lookup *esi *(esi+4))
 9730 #?       (write-buffered Stderr "created typeinfo fields at ")
 9731 #?       (write-int32-hex-buffered Stderr %esi)
 9732 #?       (write-buffered Stderr " for ")
 9733 #?       (write-int32-hex-buffered Stderr *(ebp+8))
 9734 #?       (write-buffered Stderr Newline)
 9735 #?       (flush Stderr)
 9736     }
 9737     # *out = src
 9738     # . *edi = *src
 9739     8b/-> *esi 0/r32/eax
 9740     89/<- *edi 0/r32/eax
 9741     8b/-> *(esi+4) 0/r32/eax
 9742     89/<- *(edi+4) 0/r32/eax
 9743 $find-or-create-typeinfo-fields:end:
 9744     # . restore registers
 9745     5f/pop-to-edi
 9746     5e/pop-to-esi
 9747     58/pop-to-eax
 9748     # . epilogue
 9749     89/<- %esp 5/r32/ebp
 9750     5d/pop-to-ebp
 9751     c3/return
 9752 
 9753 populate-mu-type:  # in: (addr stream byte), t: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
 9754     # pseudocode:
 9755     #   var line: (stream byte 512)
 9756     #   curr-index = 0
 9757     #   while true
 9758     #     clear-stream(line)
 9759     #     read-line-buffered(in, line)
 9760     #     if line->write == 0
 9761     #       abort
 9762     #     word-slice = next-mu-token(line)
 9763     #     if slice-empty?(word-slice)               # end of line
 9764     #       continue
 9765     #     if slice-equal?(word-slice, "}")
 9766     #       break
 9767     #     var v: (handle var) = parse-var-with-type(word-slice, line)
 9768     #     var r: (handle typeinfo-fields) = find-or-create-typeinfo-fields(t, word-slice/v->name)
 9769     #     TODO: ensure that r->first is null
 9770     #     r->index = curr-index
 9771     #     curr-index++
 9772     #     r->input-var = v
 9773     #     if r->output-var == 0
 9774     #       r->output-var = new literal
 9775     #     TODO: ensure nothing else in line
 9776     # t->total-size-in-bytes = -2 (not yet initialized)
 9777     #
 9778     # . prologue
 9779     55/push-ebp
 9780     89/<- %ebp 4/r32/esp
 9781     # var curr-index: int at *(ebp-4)
 9782     68/push 0/imm32
 9783     # . save registers
 9784     50/push-eax
 9785     51/push-ecx
 9786     52/push-edx
 9787     53/push-ebx
 9788     56/push-esi
 9789     57/push-edi
 9790     # edi = t
 9791     8b/-> *(ebp+0xc) 7/r32/edi
 9792     # var line/ecx: (stream byte 512)
 9793     81 5/subop/subtract %esp 0x200/imm32
 9794     68/push 0x200/imm32/size
 9795     68/push 0/imm32/read
 9796     68/push 0/imm32/write
 9797     89/<- %ecx 4/r32/esp
 9798     # var word-slice/edx: slice
 9799     68/push 0/imm32/end
 9800     68/push 0/imm32/start
 9801     89/<- %edx 4/r32/esp
 9802     # var v/esi: (handle var)
 9803     68/push 0/imm32
 9804     68/push 0/imm32
 9805     89/<- %esi 4/r32/esp
 9806     # var r/ebx: (handle typeinfo-entry)
 9807     68/push 0/imm32
 9808     68/push 0/imm32
 9809     89/<- %ebx 4/r32/esp
 9810     {
 9811 $populate-mu-type:line-loop:
 9812       (clear-stream %ecx)
 9813       (read-line-buffered *(ebp+8) %ecx)
 9814       # if (line->write == 0) abort
 9815       81 7/subop/compare *ecx 0/imm32
 9816       0f 84/jump-if-= $populate-mu-type:abort/disp32
 9817 +--  6 lines: #?       # dump line ------------------------------------------------------------------------------------------------------------------------------------------------------
 9823       (next-mu-token %ecx %edx)
 9824       # if slice-empty?(word-slice) continue
 9825       (slice-empty? %edx)  # => eax
 9826       3d/compare-eax-and 0/imm32
 9827       0f 85/jump-if-!= loop/disp32
 9828       # if slice-equal?(word-slice, "}") break
 9829       (slice-equal? %edx "}")
 9830       3d/compare-eax-and 0/imm32
 9831       0f 85/jump-if-!= break/disp32
 9832 $populate-mu-type:parse-element:
 9833       # v = parse-var-with-type(word-slice, first-line)
 9834       # must do this first to strip the trailing ':' from word-slice before
 9835       # using it in find-or-create-typeinfo-fields below
 9836       # TODO: clean up that mutation in parse-var-with-type
 9837       (parse-var-with-type %edx %ecx %esi *(ebp+0x10) *(ebp+0x14))  # => eax
 9838       # var tmp/ecx
 9839       51/push-ecx
 9840 $populate-mu-type:create-typeinfo-fields:
 9841       # var r/ebx: (handle typeinfo-entry)
 9842       (find-or-create-typeinfo-fields %edi %edx %ebx)
 9843       # r->index = curr-index
 9844       (lookup *ebx *(ebx+4))  # => eax
 9845       8b/-> *(ebp-4) 1/r32/ecx
 9846 #?       (write-buffered Stderr "saving index ")
 9847 #?       (write-int32-hex-buffered Stderr %ecx)
 9848 #?       (write-buffered Stderr " at ")
 9849 #?       (write-int32-hex-buffered Stderr %edi)
 9850 #?       (write-buffered Stderr Newline)
 9851 #?       (flush Stderr)
 9852       89/<- *(eax+8) 1/r32/ecx  # Typeinfo-entry-index
 9853       # ++curr-index
 9854       ff 0/subop/increment *(ebp-4)
 9855 $populate-mu-type:set-input-type:
 9856       # r->input-var = v
 9857       8b/-> *esi 1/r32/ecx
 9858       89/<- *eax 1/r32/ecx  # Typeinfo-entry-input-var
 9859       8b/-> *(esi+4) 1/r32/ecx
 9860       89/<- *(eax+4) 1/r32/ecx  # Typeinfo-entry-input-var
 9861       59/pop-to-ecx
 9862       {
 9863 $populate-mu-type:create-output-type:
 9864         # if (r->output-var == 0) create a new var with some placeholder data
 9865         81 7/subop/compare *(eax+0xc) 0/imm32  # Typeinfo-entry-output-var
 9866         75/jump-if-!= break/disp8
 9867         8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
 9868         (new-literal Heap %edx %eax)
 9869       }
 9870       e9/jump loop/disp32
 9871     }
 9872 $populate-mu-type:invalidate-total-size-in-bytes:
 9873     # Offsets and total size may not be accurate here since we may not yet
 9874     # have encountered the element types.
 9875     # We'll recompute them separately after parsing the entire program.
 9876     c7 0/subop/copy *(edi+0xc) -2/imm32/uninitialized  # Typeinfo-total-size-in-bytes
 9877 $populate-mu-type:end:
 9878     # . reclaim locals
 9879     81 0/subop/add %esp 0x224/imm32
 9880     # . restore registers
 9881     5f/pop-to-edi
 9882     5e/pop-to-esi
 9883     5b/pop-to-ebx
 9884     5a/pop-to-edx
 9885     59/pop-to-ecx
 9886     58/pop-to-eax
 9887     # reclaim curr-index
 9888     81 0/subop/add %esp 4/imm32
 9889     # . epilogue
 9890     89/<- %esp 5/r32/ebp
 9891     5d/pop-to-ebp
 9892     c3/return
 9893 
 9894 $populate-mu-type:abort:
 9895     # error("unexpected top-level command: " word-slice "\n")
 9896     (write-buffered *(ebp+0x10) "incomplete type definition '")
 9897     (type-name *edi)  # Typeinfo-id => eax
 9898     (write-buffered *(ebp+0x10) %eax)
 9899     (write-buffered *(ebp+0x10) "\n")
 9900     (flush *(ebp+0x10))
 9901     (stop *(ebp+0x14) 1)
 9902     # never gets here
 9903 
 9904 type-name:  # index: int -> result/eax: (addr array byte)
 9905     # . prologue
 9906     55/push-ebp
 9907     89/<- %ebp 4/r32/esp
 9908     #
 9909     (index Type-id *(ebp+8))
 9910 $type-name:end:
 9911     # . epilogue
 9912     89/<- %esp 5/r32/ebp
 9913     5d/pop-to-ebp
 9914     c3/return
 9915 
 9916 index:  # arr: (addr stream (handle array byte)), index: int -> result/eax: (addr array byte)
 9917     # . prologue
 9918     55/push-ebp
 9919     89/<- %ebp 4/r32/esp
 9920     # . save registers
 9921     56/push-esi
 9922     # TODO: bounds-check index
 9923     # esi = arr
 9924     8b/-> *(ebp+8) 6/r32/esi
 9925     # eax = index
 9926     8b/-> *(ebp+0xc) 0/r32/eax
 9927     # eax = *(arr + 12 + index)
 9928     8b/-> *(esi+eax+0xc) 0/r32/eax
 9929 $index:end:
 9930     # . restore registers
 9931     5e/pop-to-esi
 9932     # . epilogue
 9933     89/<- %esp 5/r32/ebp
 9934     5d/pop-to-ebp
 9935     c3/return
 9936 
 9937 #######################################################
 9938 # Compute type sizes
 9939 #######################################################
 9940 
 9941 # Compute the sizes of all user-defined types.
 9942 # We'll need the sizes of their elements, which may be other user-defined
 9943 # types, which we will compute as needed.
 9944 
 9945 # Initially, all user-defined types have their sizes set to -2 (invalid)
 9946 populate-mu-type-sizes:  # err: (addr buffered-file), ed: (addr exit-descriptor)
 9947     # . prologue
 9948     55/push-ebp
 9949     89/<- %ebp 4/r32/esp
 9950 $populate-mu-type-sizes:total-sizes:
 9951     # var curr/eax: (addr typeinfo) = lookup(Program->types)
 9952     (lookup *_Program-types *_Program-types->payload)  # => eax
 9953     {
 9954       # if (curr == null) break
 9955       3d/compare-eax-and 0/imm32/null
 9956       74/jump-if-= break/disp8
 9957       (populate-mu-type-sizes-in-type %eax *(ebp+8) *(ebp+0xc))
 9958       # curr = lookup(curr->next)
 9959       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
 9960       eb/jump loop/disp8
 9961     }
 9962 $populate-mu-type-sizes:offsets:
 9963     # curr = *Program->types
 9964     (lookup *_Program-types *_Program-types->payload)  # => eax
 9965     {
 9966       # if (curr == null) break
 9967       3d/compare-eax-and 0/imm32/null
 9968       74/jump-if-= break/disp8
 9969       (populate-mu-type-offsets %eax *(ebp+8) *(ebp+0xc))
 9970       # curr = curr->next
 9971       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
 9972       eb/jump loop/disp8
 9973     }
 9974 $populate-mu-type-sizes:end:
 9975     # . epilogue
 9976     89/<- %esp 5/r32/ebp
 9977     5d/pop-to-ebp
 9978     c3/return
 9979 
 9980 # compute sizes of all fields, recursing as necessary
 9981 # sum up all their sizes to arrive at total size
 9982 # fields may be out of order, but that doesn't affect the answer
 9983 populate-mu-type-sizes-in-type:  # T: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
 9984     # . prologue
 9985     55/push-ebp
 9986     89/<- %ebp 4/r32/esp
 9987     # . save registers
 9988     50/push-eax
 9989     51/push-ecx
 9990     52/push-edx
 9991     56/push-esi
 9992     57/push-edi
 9993     # esi = T
 9994     8b/-> *(ebp+8) 6/r32/esi
 9995     # if T is already computed, return
 9996     81 7/subop/compare *(esi+0xc) 0/imm32  # Typeinfo-total-size-in-bytes
 9997     0f 8d/jump-if->= $populate-mu-type-sizes-in-type:end/disp32
 9998     # if T is being computed, abort
 9999     81 7/subop/compare *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
10000     0f 84/jump-if-= $populate-mu-type-sizes-in-type:abort/disp32
10001     # tag T (-2 to -1) to avoid infinite recursion
10002     c7 0/subop/copy *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
10003     # var total-size/edi: int = 0
10004     bf/copy-to-edi 0/imm32
10005     # - for every field, if it's a user-defined type, compute its size
10006     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
10007     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
10008     89/<- %ecx 0/r32/eax
10009     # var table-size/edx: int = table->write
10010     8b/-> *ecx 2/r32/edx  # stream-write
10011     # var curr/ecx: (addr table_row) = table->data
10012     8d/copy-address *(ecx+0xc) 1/r32/ecx
10013     # var max/edx: (addr table_row) = table->data + table->write
10014     8d/copy-address *(ecx+edx) 2/r32/edx
10015     {
10016 $populate-mu-type-sizes-in-type:loop:
10017       # if (curr >= max) break
10018       39/compare %ecx 2/r32/edx
10019       73/jump-if-addr>= break/disp8
10020       # var t/eax: (addr typeinfo-entry) = lookup(curr->value)
10021       (lookup *(ecx+8) *(ecx+0xc))  # => eax
10022       # if (t->input-var == 0) silently ignore it; we'll emit a nice error message while type-checking
10023       81 7/subop/compare *eax 0/imm32  # Typeinfo-entry-input-var
10024       74/jump-if-= $populate-mu-type-sizes-in-type:end/disp8
10025       # compute size of t->input-var
10026       (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
10027       (compute-size-of-var %eax)  # => eax
10028       # result += eax
10029       01/add-to %edi 0/r32/eax
10030       # curr += row-size
10031       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
10032       #
10033       eb/jump loop/disp8
10034     }
10035     # - save result
10036     89/<- *(esi+0xc) 7/r32/edi  # Typeinfo-total-size-in-bytes
10037 $populate-mu-type-sizes-in-type:end:
10038     # . restore registers
10039     5f/pop-to-edi
10040     5e/pop-to-esi
10041     5a/pop-to-edx
10042     59/pop-to-ecx
10043     58/pop-to-eax
10044     # . epilogue
10045     89/<- %esp 5/r32/ebp
10046     5d/pop-to-ebp
10047     c3/return
10048 
10049 $populate-mu-type-sizes-in-type:abort:
10050     (write-buffered *(ebp+0xc) "cycle in type definitions\n")
10051     (flush *(ebp+0xc))
10052     (stop *(ebp+0x10) 1)
10053     # never gets here
10054 
10055 # Analogous to size-of, except we need to compute what size-of can just read
10056 # off the right data structures.
10057 compute-size-of-var:  # in: (addr var) -> result/eax: int
10058     # . prologue
10059     55/push-ebp
10060     89/<- %ebp 4/r32/esp
10061     # . push registers
10062     51/push-ecx
10063     # var t/ecx: (addr tree type-id) = lookup(v->type)
10064     8b/-> *(ebp+8) 1/r32/ecx
10065     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
10066     89/<- %ecx 0/r32/eax
10067     # if (t->is-atom == false) t = lookup(t->left)
10068     {
10069       81 7/subop/compare *ecx 0/imm32/false  # Tree-is-atom
10070       75/jump-if-!= break/disp8
10071       (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
10072       89/<- %ecx 0/r32/eax
10073     }
10074     # TODO: ensure t is an atom
10075     (compute-size-of-type-id *(ecx+4))  # Tree-value => eax
10076 $compute-size-of-var:end:
10077     # . restore registers
10078     59/pop-to-ecx
10079     # . epilogue
10080     89/<- %esp 5/r32/ebp
10081     5d/pop-to-ebp
10082     c3/return
10083 
10084 compute-size-of-type-id:  # t: type-id -> result/eax: int
10085     # . prologue
10086     55/push-ebp
10087     89/<- %ebp 4/r32/esp
10088     # . save registers
10089     51/push-ecx
10090     # var out/ecx: (handle typeinfo)
10091     68/push 0/imm32
10092     68/push 0/imm32
10093     89/<- %ecx 4/r32/esp
10094     # eax = t
10095     8b/-> *(ebp+8) 0/r32/eax
10096     # if t is a literal, return 0
10097     3d/compare-eax-and 0/imm32/literal
10098     0f 84/jump-if-= $compute-size-of-type-id:end/disp32  # eax changes type from type-id to int
10099     # if t is a byte, return 4 (because we don't really support non-multiples of 4)
10100     3d/compare-eax-and 8/imm32/byte
10101     {
10102       75/jump-if-!= break/disp8
10103       b8/copy-to-eax 4/imm32
10104       eb/jump $compute-size-of-type-id:end/disp8
10105     }
10106     # if t is a handle, return 8
10107     3d/compare-eax-and 4/imm32/handle
10108     {
10109       75/jump-if-!= break/disp8
10110       b8/copy-to-eax 8/imm32
10111       eb/jump $compute-size-of-type-id:end/disp8  # eax changes type from type-id to int
10112     }
10113     # if t is a user-defined type, compute its size
10114     # TODO: support non-atom type
10115     (find-typeinfo %eax %ecx)
10116     {
10117       81 7/subop/compare *ecx 0/imm32
10118       74/jump-if-= break/disp8
10119 $compute-size-of-type-id:user-defined:
10120       (populate-mu-type-sizes %eax)
10121       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
10122       eb/jump $compute-size-of-type-id:end/disp8
10123     }
10124     # otherwise return the word size
10125     b8/copy-to-eax 4/imm32
10126 $compute-size-of-type-id:end:
10127     # . reclaim locals
10128     81 0/subop/add %esp 8/imm32
10129     # . restore registers
10130     59/pop-to-ecx
10131     # . epilogue
10132     89/<- %esp 5/r32/ebp
10133     5d/pop-to-ebp
10134     c3/return
10135 
10136 # at this point we have total sizes for all user-defined types
10137 # compute offsets for each element
10138 # complication: fields may be out of order
10139 populate-mu-type-offsets:  # in: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
10140     # . prologue
10141     55/push-ebp
10142     89/<- %ebp 4/r32/esp
10143     # . save registers
10144     50/push-eax
10145     51/push-ecx
10146     52/push-edx
10147     53/push-ebx
10148     56/push-esi
10149     57/push-edi
10150 #?     (dump-typeinfos "aaa\n")
10151     # var curr-offset/edi: int = 0
10152     bf/copy-to-edi 0/imm32
10153     # var table/ecx: (addr table string_key (handle typeinfo-entry)) = lookup(in->fields)
10154     8b/-> *(ebp+8) 1/r32/ecx
10155     (lookup *(ecx+4) *(ecx+8))  # Typeinfo-fields Typeinfo-fields => eax
10156     89/<- %ecx 0/r32/eax
10157     # var num-elems/edx: int = table->write / Typeinfo-fields-row-size
10158     8b/-> *ecx 2/r32/edx  # stream-write
10159     c1 5/subop/shift-right-logical  %edx 4/imm8
10160     # var i/ebx: int = 0
10161     bb/copy-to-ebx 0/imm32
10162     {
10163 $populate-mu-type-offsets:loop:
10164       39/compare %ebx 2/r32/edx
10165       0f 8d/jump-if->= break/disp32
10166 #?       (write-buffered Stderr "looking up index ")
10167 #?       (write-int32-hex-buffered Stderr %ebx)
10168 #?       (write-buffered Stderr " in ")
10169 #?       (write-int32-hex-buffered Stderr *(ebp+8))
10170 #?       (write-buffered Stderr Newline)
10171 #?       (flush Stderr)
10172       # var v/esi: (addr typeinfo-entry)
10173       (locate-typeinfo-entry-with-index %ecx %ebx *(ebp+0xc) *(ebp+0x10))  # => eax
10174       89/<- %esi 0/r32/eax
10175       # if v is null, silently move on; we'll emit a nice error message while type-checking
10176       81 7/subop/compare %esi 0/imm32  # Typeinfo-entry-input-var
10177       74/jump-if-= $populate-mu-type-offsets:end/disp8
10178       # if (v->input-var == 0) silently ignore v; we'll emit a nice error message while type-checking
10179       81 7/subop/compare *esi 0/imm32  # Typeinfo-entry-input-var
10180       74/jump-if-= $populate-mu-type-offsets:end/disp8
10181       # v->output-var->offset = curr-offset
10182       # . eax: (addr var)
10183       (lookup *(esi+0xc) *(esi+0x10))  # Typeinfo-entry-output-var Typeinfo-entry-output-var => eax
10184       89/<- *(eax+0x14) 7/r32/edi  # Var-offset
10185       # curr-offset += size-of(v->input-var)
10186       (lookup *esi *(esi+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
10187       (size-of %eax)  # => eax
10188       01/add-to %edi 0/r32/eax
10189       # ++i
10190       43/increment-ebx
10191       e9/jump loop/disp32
10192     }
10193 $populate-mu-type-offsets:end:
10194     # . restore registers
10195     5f/pop-to-edi
10196     5e/pop-to-esi
10197     5b/pop-to-ebx
10198     5a/pop-to-edx
10199     59/pop-to-ecx
10200     58/pop-to-eax
10201     # . epilogue
10202     89/<- %esp 5/r32/ebp
10203     5d/pop-to-ebp
10204     c3/return
10205 
10206 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)
10207     # . prologue
10208     55/push-ebp
10209     89/<- %ebp 4/r32/esp
10210     # . save registers
10211     51/push-ecx
10212     52/push-edx
10213     53/push-ebx
10214     56/push-esi
10215     57/push-edi
10216     # esi = table
10217     8b/-> *(ebp+8) 6/r32/esi
10218     # var curr/ecx: (addr row (handle array byte) (handle typeinfo-entry)) = table->data
10219     8d/copy-address *(esi+0xc) 1/r32/ecx
10220     # var max/edx: (addr byte) = &table->data[table->write]
10221     8b/-> *esi 2/r32/edx
10222     8d/copy-address *(ecx+edx) 2/r32/edx
10223     {
10224 $locate-typeinfo-entry-with-index:loop:
10225       39/compare %ecx 2/r32/edx
10226       73/jump-if-addr>= break/disp8
10227       # var v/eax: (addr typeinfo-entry)
10228       (lookup *(ecx+8) *(ecx+0xc))  # => eax
10229       # if (v->index == idx) return v
10230       8b/-> *(eax+8) 3/r32/ebx  # Typeinfo-entry-index
10231 #?       (write-buffered Stderr "comparing ")
10232 #?       (write-int32-hex-buffered Stderr %ebx)
10233 #?       (write-buffered Stderr " and ")
10234 #?       (write-int32-hex-buffered Stderr *(ebp+0xc))
10235 #?       (write-buffered Stderr Newline)
10236 #?       (flush Stderr)
10237       39/compare *(ebp+0xc) 3/r32/ebx
10238       74/jump-if-= $locate-typeinfo-entry-with-index:end/disp8
10239       # curr += Typeinfo-entry-size
10240       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-entry-size
10241       #
10242       eb/jump loop/disp8
10243     }
10244     # return 0
10245     b8/copy-to-eax 0/imm32
10246 $locate-typeinfo-entry-with-index:end:
10247 #?     (write-buffered Stderr "returning ")
10248 #?     (write-int32-hex-buffered Stderr %eax)
10249 #?     (write-buffered Stderr Newline)
10250 #?     (flush Stderr)
10251     # . restore registers
10252     5f/pop-to-edi
10253     5e/pop-to-esi
10254     5b/pop-to-ebx
10255     5a/pop-to-edx
10256     59/pop-to-ecx
10257     # . epilogue
10258     89/<- %esp 5/r32/ebp
10259     5d/pop-to-ebp
10260     c3/return
10261 
10262 dump-typeinfos:  # hdr: (addr array byte)
10263     # . prologue
10264     55/push-ebp
10265     89/<- %ebp 4/r32/esp
10266     # . save registers
10267     50/push-eax
10268     #
10269     (write-buffered Stderr *(ebp+8))
10270     (flush Stderr)
10271     # var curr/eax: (addr typeinfo) = lookup(Program->types)
10272     (lookup *_Program-types *_Program-types->payload)  # => eax
10273     {
10274       # if (curr == null) break
10275       3d/compare-eax-and 0/imm32
10276       74/jump-if-= break/disp8
10277       (write-buffered Stderr "---\n")
10278       (flush Stderr)
10279       (dump-typeinfo %eax)
10280       # curr = lookup(curr->next)
10281       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
10282       eb/jump loop/disp8
10283     }
10284 $dump-typeinfos:end:
10285     # . restore registers
10286     58/pop-to-eax
10287     # . epilogue
10288     89/<- %esp 5/r32/ebp
10289     5d/pop-to-ebp
10290     c3/return
10291 
10292 dump-typeinfo:  # in: (addr typeinfo)
10293     # . prologue
10294     55/push-ebp
10295     89/<- %ebp 4/r32/esp
10296     # . save registers
10297     50/push-eax
10298     51/push-ecx
10299     52/push-edx
10300     53/push-ebx
10301     56/push-esi
10302     57/push-edi
10303     # esi = in
10304     8b/-> *(ebp+8) 6/r32/esi
10305     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
10306     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
10307     89/<- %ecx 0/r32/eax
10308     (write-buffered Stderr "id:")
10309     (write-int32-hex-buffered Stderr *esi)
10310     (write-buffered Stderr "\n")
10311     (write-buffered Stderr "fields @ ")
10312     (write-int32-hex-buffered Stderr %ecx)
10313     (write-buffered Stderr Newline)
10314     (flush Stderr)
10315     (write-buffered Stderr "  write: ")
10316     (write-int32-hex-buffered Stderr *ecx)
10317     (write-buffered Stderr Newline)
10318     (flush Stderr)
10319     (write-buffered Stderr "  read: ")
10320     (write-int32-hex-buffered Stderr *(ecx+4))
10321     (write-buffered Stderr Newline)
10322     (flush Stderr)
10323     (write-buffered Stderr "  size: ")
10324     (write-int32-hex-buffered Stderr *(ecx+8))
10325     (write-buffered Stderr Newline)
10326     (flush Stderr)
10327     # var table-size/edx: int = table->write
10328     8b/-> *ecx 2/r32/edx  # stream-write
10329     # var curr/ecx: (addr table_row) = table->data
10330     8d/copy-address *(ecx+0xc) 1/r32/ecx
10331     # var max/edx: (addr table_row) = table->data + table->write
10332     8d/copy-address *(ecx+edx) 2/r32/edx
10333     {
10334 $dump-typeinfo:loop:
10335       # if (curr >= max) break
10336       39/compare %ecx 2/r32/edx
10337       0f 83/jump-if-addr>= break/disp32
10338       (write-buffered Stderr "  row:\n")
10339       (write-buffered Stderr "    key: ")
10340       (write-int32-hex-buffered Stderr *ecx)
10341       (write-buffered Stderr ",")
10342       (write-int32-hex-buffered Stderr *(ecx+4))
10343       (write-buffered Stderr " = '")
10344       (lookup *ecx *(ecx+4))
10345       (write-buffered Stderr %eax)
10346       (write-buffered Stderr "' @ ")
10347       (write-int32-hex-buffered Stderr %eax)
10348       (write-buffered Stderr Newline)
10349       (flush Stderr)
10350       (write-buffered Stderr "    value: ")
10351       (write-int32-hex-buffered Stderr *(ecx+8))
10352       (write-buffered Stderr ",")
10353       (write-int32-hex-buffered Stderr *(ecx+0xc))
10354       (write-buffered Stderr " = typeinfo-entry@")
10355       (lookup *(ecx+8) *(ecx+0xc))
10356       (write-int32-hex-buffered Stderr %eax)
10357       (write-buffered Stderr Newline)
10358       (flush Stderr)
10359       (write-buffered Stderr "        input var@")
10360       (dump-var 5 %eax)
10361       (lookup *(ecx+8) *(ecx+0xc))
10362       (write-buffered Stderr "        index: ")
10363       (write-int32-hex-buffered Stderr *(eax+8))
10364       (write-buffered Stderr Newline)
10365       (flush Stderr)
10366       (write-buffered Stderr "        output var@")
10367       8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
10368       (dump-var 5 %eax)
10369       (flush Stderr)
10370       # curr += row-size
10371       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
10372       #
10373       e9/jump loop/disp32
10374     }
10375 $dump-typeinfo:end:
10376     # . restore registers
10377     5f/pop-to-edi
10378     5e/pop-to-esi
10379     5b/pop-to-ebx
10380     5a/pop-to-edx
10381     59/pop-to-ecx
10382     58/pop-to-eax
10383     # . epilogue
10384     89/<- %esp 5/r32/ebp
10385     5d/pop-to-ebp
10386     c3/return
10387 
10388 dump-var:  # indent: int, v: (addr handle var)
10389     # . prologue
10390     55/push-ebp
10391     89/<- %ebp 4/r32/esp
10392     # . save registers
10393     50/push-eax
10394     53/push-ebx
10395     # eax = v
10396     8b/-> *(ebp+0xc) 0/r32/eax
10397     #
10398     (write-int32-hex-buffered Stderr *eax)
10399     (write-buffered Stderr ",")
10400     (write-int32-hex-buffered Stderr *(eax+4))
10401     (write-buffered Stderr "->")
10402     (lookup *eax *(eax+4))
10403     (write-int32-hex-buffered Stderr %eax)
10404     (write-buffered Stderr Newline)
10405     (flush Stderr)
10406     {
10407       3d/compare-eax-and 0/imm32
10408       0f 84/jump-if-= break/disp32
10409       (emit-indent Stderr *(ebp+8))
10410       (write-buffered Stderr "name: ")
10411       89/<- %ebx 0/r32/eax
10412       (write-int32-hex-buffered Stderr *ebx)  # Var-name
10413       (write-buffered Stderr ",")
10414       (write-int32-hex-buffered Stderr *(ebx+4))  # Var-name
10415       (write-buffered Stderr "->")
10416       (lookup *ebx *(ebx+4))  # Var-name
10417       (write-int32-hex-buffered Stderr %eax)
10418       {
10419         3d/compare-eax-and 0/imm32
10420         74/jump-if-= break/disp8
10421         (write-buffered Stderr Space)
10422         (write-buffered Stderr %eax)
10423       }
10424       (write-buffered Stderr Newline)
10425       (flush Stderr)
10426       (emit-indent Stderr *(ebp+8))
10427       (write-buffered Stderr "block depth: ")
10428       (write-int32-hex-buffered Stderr *(ebx+0x10))  # Var-block-depth
10429       (write-buffered Stderr Newline)
10430       (flush Stderr)
10431       (emit-indent Stderr *(ebp+8))
10432       (write-buffered Stderr "stack offset: ")
10433       (write-int32-hex-buffered Stderr *(ebx+0x14))  # Var-offset
10434       (write-buffered Stderr Newline)
10435       (flush Stderr)
10436       (emit-indent Stderr *(ebp+8))
10437       (write-buffered Stderr "reg: ")
10438       (write-int32-hex-buffered Stderr *(ebx+0x18))  # Var-register
10439       (write-buffered Stderr ",")
10440       (write-int32-hex-buffered Stderr *(ebx+0x1c))  # Var-register
10441       (write-buffered Stderr "->")
10442       (flush Stderr)
10443       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register
10444       (write-int32-hex-buffered Stderr %eax)
10445       {
10446         3d/compare-eax-and 0/imm32
10447         74/jump-if-= break/disp8
10448         (write-buffered Stderr Space)
10449         (write-buffered Stderr %eax)
10450       }
10451       (write-buffered Stderr Newline)
10452       (flush Stderr)
10453     }
10454 $dump-var:end:
10455     # . restore registers
10456     5b/pop-to-ebx
10457     58/pop-to-eax
10458     # . epilogue
10459     89/<- %esp 5/r32/ebp
10460     5d/pop-to-ebp
10461     c3/return
10462 
10463 #######################################################
10464 # Type-checking
10465 #######################################################
10466 
10467 check-mu-types:  # err: (addr buffered-file), ed: (addr exit-descriptor)
10468     # . prologue
10469     55/push-ebp
10470     89/<- %ebp 4/r32/esp
10471     # . save registers
10472     50/push-eax
10473     # var curr/eax: (addr function) = *Program->functions
10474     (lookup *_Program-functions *_Program-functions->payload)  # => eax
10475     {
10476 $check-mu-types:loop:
10477       # if (curr == null) break
10478       3d/compare-eax-and 0/imm32
10479       0f 84/jump-if-= break/disp32
10480       (check-mu-function %eax *(ebp+8) *(ebp+0xc))
10481       # curr = lookup(curr->next)
10482       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
10483       e9/jump loop/disp32
10484     }
10485 $check-mu-types:end:
10486     # . restore registers
10487     58/pop-to-eax
10488     # . epilogue
10489     89/<- %esp 5/r32/ebp
10490     5d/pop-to-ebp
10491     c3/return
10492 
10493 check-mu-function:  # fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
10494     # . prologue
10495     55/push-ebp
10496     89/<- %ebp 4/r32/esp
10497     # . save registers
10498     50/push-eax
10499     # eax = f
10500     8b/-> *(ebp+8) 0/r32/eax
10501     # TODO: anything to check in header?
10502     # var body/eax: (addr block) = lookup(f->body)
10503     (lookup *(eax+0x18) *(eax+0x1c))  # Function-body Function-body => eax
10504     (check-mu-block %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10))
10505 $check-mu-function:end:
10506     # . restore registers
10507     58/pop-to-eax
10508     # . epilogue
10509     89/<- %esp 5/r32/ebp
10510     5d/pop-to-ebp
10511     c3/return
10512 
10513 check-mu-block:  # block: (addr block), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
10514     # . prologue
10515     55/push-ebp
10516     89/<- %ebp 4/r32/esp
10517     # . save registers
10518     50/push-eax
10519     # eax = block
10520     8b/-> *(ebp+8) 0/r32/eax
10521     # var stmts/eax: (addr list stmt) = lookup(block->statements)
10522     (lookup *(eax+4) *(eax+8))  # Block-stmts Block-stmts => eax
10523     #
10524     {
10525 $check-mu-block:check-empty:
10526       3d/compare-eax-and 0/imm32
10527       0f 84/jump-if-= break/disp32
10528       # emit block->statements
10529       (check-mu-stmt-list %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
10530     }
10531 $check-mu-block:end:
10532     # . restore registers
10533     58/pop-to-eax
10534     # . epilogue
10535     89/<- %esp 5/r32/ebp
10536     5d/pop-to-ebp
10537     c3/return
10538 
10539 check-mu-stmt-list:  # stmts: (addr list stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
10540     # . prologue
10541     55/push-ebp
10542     89/<- %ebp 4/r32/esp
10543     # . save registers
10544     50/push-eax
10545     56/push-esi
10546     # esi = stmts
10547     8b/-> *(ebp+8) 6/r32/esi
10548     {
10549 $check-mu-stmt-list:loop:
10550       81 7/subop/compare %esi 0/imm32
10551       0f 84/jump-if-= break/disp32
10552       # var curr-stmt/eax: (addr stmt) = lookup(stmts->value)
10553       (lookup *esi *(esi+4))  # List-value List-value => eax
10554       {
10555 $check-mu-stmt-list:check-for-block:
10556         81 7/subop/compare *eax 0/imm32/block  # Stmt-tag
10557         75/jump-if-!= break/disp8
10558 $check-mu-stmt-list:block:
10559         (check-mu-block %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
10560         eb/jump $check-mu-stmt-list:continue/disp8
10561       }
10562       {
10563 $check-mu-stmt-list:check-for-stmt1:
10564         81 7/subop/compare *eax 1/imm32/stmt1  # Stmt-tag
10565         0f 85/jump-if-!= break/disp32
10566 $check-mu-stmt-list:stmt1:
10567         (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
10568         eb/jump $check-mu-stmt-list:continue/disp8
10569       }
10570       {
10571 $check-mu-stmt-list:check-for-reg-var-def:
10572         81 7/subop/compare *eax 3/imm32/reg-var-def  # Stmt-tag
10573         0f 85/jump-if-!= break/disp32
10574 $check-mu-stmt-list:reg-var-def:
10575         (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
10576         eb/jump $check-mu-stmt-list:continue/disp8
10577       }
10578 $check-mu-stmt-list:continue:
10579       # TODO: raise an error on unrecognized Stmt-tag
10580       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
10581       89/<- %esi 0/r32/eax
10582       e9/jump loop/disp32
10583     }
10584 $check-mu-stmt-list:end:
10585     # . restore registers
10586     5e/pop-to-esi
10587     58/pop-to-eax
10588     # . epilogue
10589     89/<- %esp 5/r32/ebp
10590     5d/pop-to-ebp
10591     c3/return
10592 
10593 check-mu-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
10594     # . prologue
10595     55/push-ebp
10596     89/<- %ebp 4/r32/esp
10597     # . save registers
10598     50/push-eax
10599     # if stmt's operation matches a primitive, check against it
10600     (has-primitive-name? *(ebp+8))  # => eax
10601     3d/compare-eax-and 0/imm32/false
10602     {
10603       74/jump-if-= break/disp8
10604       (check-mu-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
10605       eb/jump $check-mu-stmt:end/disp8
10606     }
10607     # otherwise find a function to check against
10608     {
10609       # var f/edi: (addr function) = lookup(*Program->functions)
10610       (lookup *_Program-functions *_Program-functions->payload)  # => eax
10611       (find-matching-function %eax *(ebp+8))  # => eax
10612       3d/compare-eax-and 0/imm32
10613       {
10614         74/jump-if-= break/disp8
10615         (check-mu-call *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
10616         eb/jump $check-mu-stmt:end/disp8
10617       }
10618       # TODO: error on unknown function. We need to first type-check calls to SubX functions.
10619     }
10620 $check-mu-stmt:end:
10621     # . restore registers
10622     58/pop-to-eax
10623     # . epilogue
10624     89/<- %esp 5/r32/ebp
10625     5d/pop-to-ebp
10626     c3/return
10627 
10628 has-primitive-name?:  # stmt: (addr stmt) -> result/eax: boolean
10629     # . prologue
10630     55/push-ebp
10631     89/<- %ebp 4/r32/esp
10632     # . save registers
10633     51/push-ecx
10634     56/push-esi
10635     # var name/esi: (addr array byte) = lookup(stmt->operation)
10636     8b/-> *(ebp+8) 6/r32/esi
10637     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
10638     89/<- %esi 0/r32/eax
10639     # if (name == "get") return true
10640     (string-equal? %esi "get")  # => eax
10641     3d/compare-eax-and 0/imm32/false
10642     0f 85/jump-if-!= $has-primitive-name?:end/disp32
10643     # if (name == "index") return true
10644     (string-equal? %esi "index")  # => eax
10645     3d/compare-eax-and 0/imm32/false
10646     0f 85/jump-if-!= $has-primitive-name?:end/disp32
10647     # if (name == "length") return true
10648     (string-equal? %esi "length")  # => eax
10649     3d/compare-eax-and 0/imm32/false
10650     0f 85/jump-if-!= $has-primitive-name?:end/disp32
10651     # if (name == "compute-offset") return true
10652     (string-equal? %esi "compute-offset")  # => eax
10653     3d/compare-eax-and 0/imm32/false
10654     75/jump-if-!= $has-primitive-name?:end/disp8
10655     # if (name == "lookup") return true
10656     (string-equal? %esi "lookup")  # => eax
10657     3d/compare-eax-and 0/imm32/false
10658     75/jump-if-!= $has-primitive-name?:end/disp8
10659     # var curr/ecx: (addr primitive) = Primitives
10660     b9/copy-to-ecx Primitives/imm32
10661     {
10662 $has-primitive-name?:loop:
10663       # if (curr == null) break
10664       81 7/subop/compare %ecx 0/imm32
10665       74/jump-if-= break/disp8
10666       # if (primitive->name == name) return true
10667       (lookup *ecx *(ecx+4))  # Primitive-name Primitive-name => eax
10668       (string-equal? %esi %eax)  # => eax
10669       3d/compare-eax-and 0/imm32/false
10670       75/jump-if-!= $has-primitive-name?:end/disp8
10671 $has-primitive-name?:next-primitive:
10672       # curr = curr->next
10673       (lookup *(ecx+0x34) *(ecx+0x38))  # Primitive-next Primitive-next => eax
10674       89/<- %ecx 0/r32/eax
10675       #
10676       e9/jump loop/disp32
10677     }
10678     # return null
10679     b8/copy-to-eax 0/imm32
10680 $has-primitive-name?:end:
10681     # . restore registers
10682     5e/pop-to-esi
10683     59/pop-to-ecx
10684     # . epilogue
10685     89/<- %esp 5/r32/ebp
10686     5d/pop-to-ebp
10687     c3/return
10688 
10689 check-mu-primitive:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
10690     # . prologue
10691     55/push-ebp
10692     89/<- %ebp 4/r32/esp
10693     # . save registers
10694     50/push-eax
10695     51/push-ecx
10696     # var op/ecx: (addr array byte) = lookup(stmt->operation)
10697     8b/-> *(ebp+8) 0/r32/eax
10698     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
10699     89/<- %ecx 0/r32/eax
10700     # if (op == "copy") check-mu-copy-stmt
10701     {
10702       (string-equal? %ecx "copy")  # => eax
10703       3d/compare-eax-and 0/imm32/false
10704       74/jump-if-= break/disp8
10705       (check-mu-copy-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
10706       e9/jump $check-mu-primitive:end/disp32
10707     }
10708     # if (op == "copy-to") check-mu-copy-to-stmt
10709     {
10710       (string-equal? %ecx "copy-to")  # => eax
10711       3d/compare-eax-and 0/imm32/false
10712       74/jump-if-= break/disp8
10713       (check-mu-copy-to-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
10714       e9/jump $check-mu-primitive:end/disp32
10715     }
10716     # if (op == "compare") check-mu-compare-stmt
10717     {
10718       (string-equal? %ecx "compare")  # => eax
10719       3d/compare-eax-and 0/imm32/false
10720       74/jump-if-= break/disp8
10721       (check-mu-compare-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
10722       e9/jump $check-mu-primitive:end/disp32
10723     }
10724     # if (op == "address") check-mu-address-stmt
10725     {
10726       (string-equal? %ecx "address")  # => eax
10727       3d/compare-eax-and 0/imm32/false
10728       74/jump-if-= break/disp8
10729       (check-mu-address-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
10730       e9/jump $check-mu-primitive:end/disp32
10731     }
10732     # if (op == "get") check-mu-get-stmt
10733     {
10734       (string-equal? %ecx "get")  # => eax
10735       3d/compare-eax-and 0/imm32/false
10736       74/jump-if-= break/disp8
10737       (check-mu-get-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
10738       e9/jump $check-mu-primitive:end/disp32
10739     }
10740     # if (op == "index") check-mu-index-stmt
10741     {
10742       (string-equal? %ecx "index")  # => eax
10743       3d/compare-eax-and 0/imm32/false
10744       74/jump-if-= break/disp8
10745       (check-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
10746       e9/jump $check-mu-primitive:end/disp32
10747     }
10748     # if (op == "length") check-mu-length-stmt
10749     {
10750       (string-equal? %ecx "length")  # => eax
10751       3d/compare-eax-and 0/imm32/false
10752       74/jump-if-= break/disp8
10753       (check-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
10754       e9/jump $check-mu-primitive:end/disp32
10755     }
10756     # if (op == "compute-offset") check-mu-compute-offset-stmt
10757     {
10758       (string-equal? %ecx "compute-offset")  # => eax
10759       3d/compare-eax-and 0/imm32/false
10760       74/jump-if-= break/disp8
10761       (check-mu-compute-offset-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
10762       e9/jump $check-mu-primitive:end/disp32
10763     }
10764     # if (op == "lookup") check-mu-lookup-stmt
10765     {
10766       (string-equal? %ecx "lookup")  # => eax
10767       3d/compare-eax-and 0/imm32/false
10768       74/jump-if-= break/disp8
10769       (check-mu-lookup-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
10770       e9/jump $check-mu-primitive:end/disp32
10771     }
10772     # otherwise check-numberlike-stmt
10773     (check-mu-numberlike-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
10774 $check-mu-primitive:end:
10775     # . restore registers
10776     59/pop-to-ecx
10777     58/pop-to-eax
10778     # . epilogue
10779     89/<- %esp 5/r32/ebp
10780     5d/pop-to-ebp
10781     c3/return
10782 
10783 # by default, Mu primitives should only operate on 'number-like' types
10784 check-mu-numberlike-primitive:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
10785     # . prologue
10786     55/push-ebp
10787     89/<- %ebp 4/r32/esp
10788     # . save registers
10789     50/push-eax
10790     51/push-ecx
10791     56/push-esi
10792     # esi = stmt
10793     8b/-> *(ebp+8) 6/r32/esi
10794     # var gas/ecx: int = 2
10795     b9/copy-to-ecx 2/imm32
10796     # - check at most 1 output
10797     # var output/eax: (addr stmt-var) = stmt->outputs
10798     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
10799     {
10800       3d/compare-eax-and 0/imm32
10801       74/jump-if-= break/disp8
10802 $check-mu-numberlike-primitive:output:
10803       (check-mu-numberlike-output %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
10804       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
10805       3d/compare-eax-and 0/imm32
10806       0f 85/jump-if-!= $check-mu-numberlike-primitive:error-too-many-outputs/disp32
10807       # check output is in a register
10808       # --gas
10809       49/decrement-ecx
10810     }
10811     # - check first inout
10812     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
10813     {
10814       3d/compare-eax-and 0/imm32
10815       0f 84/jump-if-= $check-mu-numberlike-primitive:end/disp32
10816 $check-mu-numberlike-primitive:first-inout:
10817       (check-mu-numberlike-arg %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
10818       # --gas
10819       49/decrement-ecx
10820     }
10821     # - check second inout
10822     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
10823     {
10824       3d/compare-eax-and 0/imm32
10825       74/jump-if-= $check-mu-numberlike-primitive:end/disp8
10826 $check-mu-numberlike-primitive:second-inout:
10827       # is a second inout allowed?
10828       81 7/subop/compare %ecx 0/imm32
10829       0f 84/jump-if-= $check-mu-numberlike-primitive:error-too-many-inouts/disp32
10830 $check-mu-numberlike-primitive:second-inout-permitted:
10831       (check-mu-numberlike-arg %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
10832     }
10833 $check-mu-numberlike-primitive:third-inout:
10834     # if there's a third arg, raise an error
10835     81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
10836     0f 85/jump-if-!= $check-mu-numberlike-primitive:error-too-many-inouts/disp32
10837 $check-mu-numberlike-primitive:end:
10838     # . restore registers
10839     5e/pop-to-esi
10840     59/pop-to-ecx
10841     58/pop-to-eax
10842     # . epilogue
10843     89/<- %esp 5/r32/ebp
10844     5d/pop-to-ebp
10845     c3/return
10846 
10847 $check-mu-numberlike-primitive:error-too-many-inouts:
10848     (write-buffered *(ebp+0x10) "fn ")
10849     8b/-> *(ebp+0xc) 0/r32/eax
10850     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10851     (write-buffered *(ebp+0x10) %eax)
10852     (write-buffered *(ebp+0x10) ": stmt ")
10853     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
10854     (write-buffered *(ebp+0x10) %eax)
10855     (write-buffered *(ebp+0x10) ": too many inouts; most primitives support at most two arguments, across inouts and outputs\n")
10856     (flush *(ebp+0x10))
10857     (stop *(ebp+0x14) 1)
10858     # never gets here
10859 
10860 $check-mu-numberlike-primitive:error-too-many-outputs:
10861     (write-buffered *(ebp+0x10) "fn ")
10862     8b/-> *(ebp+0xc) 0/r32/eax
10863     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10864     (write-buffered *(ebp+0x10) %eax)
10865     (write-buffered *(ebp+0x10) ": stmt ")
10866     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
10867     (write-buffered *(ebp+0x10) %eax)
10868     (write-buffered *(ebp+0x10) ": too many outputs; most primitives support at most one output\n")
10869     (flush *(ebp+0x10))
10870     (stop *(ebp+0x14) 1)
10871     # never gets here
10872 
10873 check-mu-numberlike-arg:  # v: (addr stmt-var), stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
10874     # . prologue
10875     55/push-ebp
10876     89/<- %ebp 4/r32/esp
10877     # . save registers
10878     50/push-eax
10879     56/push-esi
10880     # var t/esi: (addr tree type-id) = lookup(v->value->type)
10881     8b/-> *(ebp+8) 0/r32/eax
10882     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10883     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
10884     89/<- %esi 0/r32/eax
10885 $check-mu-numberlike-arg:check-literal:
10886     # if t is an int, return
10887     (is-simple-mu-type? %esi 0)  # literal => eax
10888     3d/compare-eax-and 0/imm32/false
10889     75/jump-if-!= $check-mu-numberlike-arg:end/disp8
10890 $check-mu-numberlike-arg:check-addr:
10891     # if t is an addr and v is dereferenced, return
10892     {
10893       (is-mu-addr-type? %esi)  # => eax
10894       3d/compare-eax-and 0/imm32/false
10895       74/jump-if-= break/disp8
10896       8b/-> *(ebp+8) 0/r32/eax
10897       8b/-> *(eax+0x10) 0/r32/eax
10898       3d/compare-eax-and 0/imm32/false
10899       75/jump-if-!= $check-mu-numberlike-arg:end/disp8
10900     }
10901 $check-mu-numberlike-arg:output-checks:
10902     (check-mu-numberlike-output *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18))
10903 $check-mu-numberlike-arg:end:
10904     # . restore registers
10905     5e/pop-to-esi
10906     58/pop-to-eax
10907     # . epilogue
10908     89/<- %esp 5/r32/ebp
10909     5d/pop-to-ebp
10910     c3/return
10911 
10912 check-mu-numberlike-output:  # v: (addr stmt-var), stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
10913     # . prologue
10914     55/push-ebp
10915     89/<- %ebp 4/r32/esp
10916     # . save registers
10917     50/push-eax
10918     56/push-esi
10919     # var t/esi: (addr tree type-id) = lookup(v->value->type)
10920     8b/-> *(ebp+8) 0/r32/eax
10921     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10922     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
10923     89/<- %esi 0/r32/eax
10924 $check-mu-numberlike-output:check-int:
10925     # if t is an int, return
10926     (is-simple-mu-type? %esi 1)  # int => eax
10927     3d/compare-eax-and 0/imm32/false
10928     75/jump-if-!= $check-mu-numberlike-output:end/disp8
10929 $check-mu-numberlike-output:check-boolean:
10930     # if t is a boolean, return
10931     (is-simple-mu-type? %esi 5)  # boolean => eax
10932     3d/compare-eax-and 0/imm32/false
10933     75/jump-if-!= $check-mu-numberlike-output:end/disp8
10934 $check-mu-numberlike-output:check-byte:
10935     # if t is a byte, return
10936     (is-simple-mu-type? %esi 8)  # byte => eax
10937     3d/compare-eax-and 0/imm32/false
10938     75/jump-if-!= $check-mu-numberlike-output:end/disp8
10939     e9/jump $check-mu-numberlike-output:fail/disp32
10940 $check-mu-numberlike-output:end:
10941     # . restore registers
10942     5e/pop-to-esi
10943     58/pop-to-eax
10944     # . epilogue
10945     89/<- %esp 5/r32/ebp
10946     5d/pop-to-ebp
10947     c3/return
10948 
10949 $check-mu-numberlike-output:fail:
10950     # otherwise raise an error
10951     (write-buffered *(ebp+0x14) "fn ")
10952     8b/-> *(ebp+0x10) 0/r32/eax
10953     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10954     (write-buffered *(ebp+0x14) %eax)
10955     (write-buffered *(ebp+0x14) ": stmt ")
10956     8b/-> *(ebp+0xc) 0/r32/eax
10957     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
10958     (write-buffered *(ebp+0x14) %eax)
10959     (write-buffered *(ebp+0x14) ": only non-addr scalar args permitted\n")
10960     (flush *(ebp+0x14))
10961     (stop *(ebp+0x18) 1)
10962     # never gets here
10963 
10964 check-mu-copy-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
10965     # . prologue
10966     55/push-ebp
10967     89/<- %ebp 4/r32/esp
10968     # . save registers
10969 $check-mu-copy-stmt:end:
10970     # . restore registers
10971     # . epilogue
10972     89/<- %esp 5/r32/ebp
10973     5d/pop-to-ebp
10974     c3/return
10975 
10976 check-mu-copy-to-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
10977     # . prologue
10978     55/push-ebp
10979     89/<- %ebp 4/r32/esp
10980     # . save registers
10981 $check-mu-copy-to-stmt:end:
10982     # . restore registers
10983     # . epilogue
10984     89/<- %esp 5/r32/ebp
10985     5d/pop-to-ebp
10986     c3/return
10987 
10988 check-mu-compare-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
10989     # . prologue
10990     55/push-ebp
10991     89/<- %ebp 4/r32/esp
10992     # . save registers
10993 $check-mu-compare-stmt:end:
10994     # . restore registers
10995     # . epilogue
10996     89/<- %esp 5/r32/ebp
10997     5d/pop-to-ebp
10998     c3/return
10999 
11000 check-mu-address-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11001     # . prologue
11002     55/push-ebp
11003     89/<- %ebp 4/r32/esp
11004     # . save registers
11005 $check-mu-address-stmt:end:
11006     # . restore registers
11007     # . epilogue
11008     89/<- %esp 5/r32/ebp
11009     5d/pop-to-ebp
11010     c3/return
11011 
11012 check-mu-get-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11013     # . prologue
11014     55/push-ebp
11015     89/<- %ebp 4/r32/esp
11016     # . save registers
11017     50/push-eax
11018     51/push-ecx
11019     52/push-edx
11020     53/push-ebx
11021     56/push-esi
11022     57/push-edi
11023     # esi = stmt
11024     8b/-> *(ebp+8) 6/r32/esi
11025     # - check for 0 inouts
11026     # var base/ecx: (addr var) = stmt->inouts->value
11027     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11028     3d/compare-eax-and 0/imm32/false
11029     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-inouts/disp32
11030     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11031     89/<- %ecx 0/r32/eax
11032 $check-mu-get-stmt:check-base:
11033     # - check base type
11034     # if it's an 'addr', check that it's in a register
11035     # var base-type/ebx: (addr tree type-id) = lookup(base->type)
11036     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
11037     89/<- %ebx 0/r32/eax
11038     {
11039       81 7/subop/compare *ebx 0/imm32/false  # Tree-is-atom
11040       0f 85/jump-if-!= break/disp32
11041 $check-mu-get-stmt:base-is-compound:
11042       # if (type->left != addr) break
11043       (lookup *(ebx+4) *(ebx+8))  # Tree-left Tree-left => eax
11044       (is-simple-mu-type? %eax 2)  # => eax
11045       3d/compare-eax-and 0/imm32/false
11046       74/jump-if-= break/disp8
11047 $check-mu-get-stmt:base-is-addr:
11048       # now check for register
11049       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
11050       0f 84/jump-if-= $check-mu-get-stmt:error-base-type-addr-but-not-register/disp32
11051 $check-mu-get-stmt:base-is-addr-in-register:
11052       # type->left is now an addr; skip it
11053       (lookup *(ebx+0xc) *(ebx+0x10))  # Tree-right Tree-right => eax
11054       81 7/subop/compare *(eax+0xc) 0/imm32  # Tree-right
11055       0f 85/jump-if-!= $check-mu-get-stmt:error-bad-base/disp32
11056 $check-mu-get-stmt:base-is-addr-to-atom-in-register:
11057       (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
11058       89/<- %ebx 0/r32/eax
11059     }
11060 $check-mu-get-stmt:check-base-typeinfo:
11061     # ensure type is a container
11062     # var base-type-id/ebx: type-id = base-type->value
11063     8b/-> *(ebx+4) 3/r32/ebx  # Tree-value
11064     (is-container? %ebx)  # => eax
11065     3d/compare-eax-and 0/imm32/false
11066     0f 84/jump-if-= $check-mu-get-stmt:error-bad-base/disp32
11067     # var base-typeinfo/edx: (addr typeinfo) = find-typeinfo(base-type-id)
11068     # . var container/ecx: (handle typeinfo)
11069     68/push 0/imm32
11070     68/push 0/imm32
11071     89/<- %ecx 4/r32/esp
11072     # .
11073     (find-typeinfo %ebx %ecx)
11074     (lookup *ecx *(ecx+4))  # => eax
11075     # . reclaim container
11076     81 0/subop/add %esp 8/imm32
11077     # .
11078     89/<- %edx 0/r32/eax
11079     # var offset/ecx: (addr stmt-var) = stmt->inouts->next
11080     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11081     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
11082     89/<- %ecx 0/r32/eax
11083     # - check for 1 inout
11084     3d/compare-eax-and 0/imm32/false
11085     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-inouts/disp32
11086     # var offset/ecx: (addr var) = lookup(offset->value)
11087     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
11088     89/<- %ecx 0/r32/eax
11089     # - check for valid field
11090     81 7/subop/compare *(ecx+0x14) -1/imm32/uninitialized  # Var-offset
11091     0f 84/jump-if-= $check-mu-get-stmt:error-bad-field/disp32
11092     # - check for too many inouts
11093     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11094     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
11095     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
11096     3d/compare-eax-and 0/imm32/false
11097     0f 85/jump-if-!= $check-mu-get-stmt:error-too-many-inouts/disp32
11098     # var output/edi: (addr var) = stmt->outputs->value
11099     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
11100     # - check for 0 outputs
11101     3d/compare-eax-and 0/imm32/false
11102     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-outputs/disp32
11103     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11104     89/<- %edi 0/r32/eax
11105 $check-mu-get-stmt:check-output-type:
11106     # - check output type
11107     # must be in register
11108     (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
11109     3d/compare-eax-and 0/imm32
11110     0f 84/jump-if-= $check-mu-get-stmt:error-output-not-in-register/disp32
11111     # must have a non-atomic type
11112     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
11113     81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
11114     0f 85/jump-if-!= $check-mu-get-stmt:error-output-type-not-address/disp32
11115     # type must start with (addr ...)
11116     (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
11117     (is-simple-mu-type? %eax 2)  # => eax
11118     3d/compare-eax-and 0/imm32/false
11119     0f 84/jump-if-= $check-mu-get-stmt:error-output-type-not-address/disp32
11120 $check-mu-get-stmt:check-output-type-match:
11121     # payload of addr type must match 'type' definition
11122     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
11123     (lookup *(eax+0xc) *(eax+0x10))  # Tree-right Tree-right => eax
11124     # if (payload->right == null) payload = payload->left
11125     81 7/subop/compare *(eax+0xc) 0/imm32/null  # Tree-right
11126     {
11127       75/jump-if-!= break/disp8
11128       (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
11129     }
11130     89/<- %edi 0/r32/eax
11131     # . var output-name/ecx: (addr array byte)
11132     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
11133     89/<- %ecx 0/r32/eax
11134     # . var base-typeinfo-entry/eax: (addr handle typeinfo-entry)
11135     (lookup *(edx+4) *(edx+8))  # Typeinfo-fields Typeinfo-fields => eax
11136     (get %eax %ecx 0x10)  # => eax
11137     # .
11138     (lookup *eax *(eax+4))  # => eax
11139     (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
11140     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11141     # .
11142     (type-equal? %edi %eax)  # => eax
11143     3d/compare-eax-and 0/imm32/false
11144     0f 84/jump-if-= $check-mu-get-stmt:error-bad-output-type/disp32
11145     # - check for too many outputs
11146     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
11147     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
11148     3d/compare-eax-and 0/imm32/false
11149     0f 85/jump-if-!= $check-mu-get-stmt:error-too-many-outputs/disp32
11150 $check-mu-get-stmt:end:
11151     # . restore registers
11152     5f/pop-to-edi
11153     5e/pop-to-esi
11154     5b/pop-to-ebx
11155     5a/pop-to-edx
11156     59/pop-to-ecx
11157     58/pop-to-eax
11158     # . epilogue
11159     89/<- %esp 5/r32/ebp
11160     5d/pop-to-ebp
11161     c3/return
11162 
11163 $check-mu-get-stmt:error-too-few-inouts:
11164     (write-buffered *(ebp+0x10) "fn ")
11165     8b/-> *(ebp+0xc) 0/r32/eax
11166     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11167     (write-buffered *(ebp+0x10) %eax)
11168     (write-buffered *(ebp+0x10) ": stmt get: too few inouts (2 required)\n")
11169     (flush *(ebp+0x10))
11170     (stop *(ebp+0x14) 1)
11171     # never gets here
11172 
11173 $check-mu-get-stmt:error-too-many-inouts:
11174     (write-buffered *(ebp+0x10) "fn ")
11175     8b/-> *(ebp+0xc) 0/r32/eax
11176     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11177     (write-buffered *(ebp+0x10) %eax)
11178     (write-buffered *(ebp+0x10) ": stmt get: too many inouts (2 required)\n")
11179     (flush *(ebp+0x10))
11180     (stop *(ebp+0x14) 1)
11181     # never gets here
11182 
11183 $check-mu-get-stmt:error-too-few-outputs:
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 get: must have an output\n")
11189     (flush *(ebp+0x10))
11190     (stop *(ebp+0x14) 1)
11191     # never gets here
11192 
11193 $check-mu-get-stmt:error-too-many-outputs:
11194     (write-buffered *(ebp+0x10) "fn ")
11195     8b/-> *(ebp+0xc) 0/r32/eax
11196     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11197     (write-buffered *(ebp+0x10) %eax)
11198     (write-buffered *(ebp+0x10) ": stmt get: too many outputs (1 required)\n")
11199     (flush *(ebp+0x10))
11200     (stop *(ebp+0x14) 1)
11201     # never gets here
11202 
11203 $check-mu-get-stmt:error-bad-base:
11204     # error("fn " fn ": stmt get: var '" base->name "' must have a 'type' definition\n")
11205     (write-buffered *(ebp+0x10) "fn ")
11206     8b/-> *(ebp+0xc) 0/r32/eax
11207     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11208     (write-buffered *(ebp+0x10) %eax)
11209     (write-buffered *(ebp+0x10) ": stmt get: var '")
11210     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11211     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11212     (lookup *eax *(eax+4))  # Var-name Var-name => eax
11213     (write-buffered *(ebp+0x10) %eax)
11214     (write-buffered *(ebp+0x10) "' must have a 'type' definition\n")
11215     (flush *(ebp+0x10))
11216     (stop *(ebp+0x14) 1)
11217     # never gets here
11218 
11219 $check-mu-get-stmt:error-base-type-addr-but-not-register:
11220     (write-buffered *(ebp+0x10) "fn ")
11221     8b/-> *(ebp+0xc) 0/r32/eax
11222     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11223     (write-buffered *(ebp+0x10) %eax)
11224     (write-buffered *(ebp+0x10) ": stmt get: var '")
11225     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11226     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11227     (lookup *eax *(eax+4))  # Var-name Var-name => eax
11228     (write-buffered *(ebp+0x10) %eax)
11229     (write-buffered *(ebp+0x10) "' is an 'addr' type, and so must live in a register\n")
11230     (flush *(ebp+0x10))
11231     (stop *(ebp+0x14) 1)
11232     # never gets here
11233 
11234 $check-mu-get-stmt:error-bad-field:
11235     # error("fn " fn ": stmt get: type " type " has no member called '" curr->name "'\n")
11236     (write-buffered *(ebp+0x10) "fn ")
11237     8b/-> *(ebp+0xc) 0/r32/eax
11238     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11239     (write-buffered *(ebp+0x10) %eax)
11240     (write-buffered *(ebp+0x10) ": stmt get: type '")
11241     # . write(Type-id->data[tmp])
11242     bf/copy-to-edi Type-id/imm32
11243     (write-buffered *(ebp+0x10) *(edi+ebx<<2+0xc))
11244     # .
11245     (write-buffered *(ebp+0x10) "' has no member called '")
11246     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
11247     (write-buffered *(ebp+0x10) %eax)
11248     (write-buffered *(ebp+0x10) "'\n")
11249     (flush *(ebp+0x10))
11250     (stop *(ebp+0x14) 1)
11251     # never gets here
11252 
11253 $check-mu-get-stmt:error-output-not-in-register:
11254     (write-buffered *(ebp+0x10) "fn ")
11255     8b/-> *(ebp+0xc) 0/r32/eax
11256     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11257     (write-buffered *(ebp+0x10) %eax)
11258     (write-buffered *(ebp+0x10) ": stmt get: output '")
11259     (lookup *edi *(edi+4))  # Var-name Var-name => eax
11260     (write-buffered *(ebp+0x10) %eax)
11261     (write-buffered *(ebp+0x10) "' is not in a register\n")
11262     (flush *(ebp+0x10))
11263     (stop *(ebp+0x14) 1)
11264     # never gets here
11265 
11266 $check-mu-get-stmt:error-output-type-not-address:
11267     (write-buffered *(ebp+0x10) "fn ")
11268     8b/-> *(ebp+0xc) 0/r32/eax
11269     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11270     (write-buffered *(ebp+0x10) %eax)
11271     (write-buffered *(ebp+0x10) ": stmt get: output must be an address\n")
11272     (flush *(ebp+0x10))
11273     (stop *(ebp+0x14) 1)
11274     # never gets here
11275 
11276 $check-mu-get-stmt:error-bad-output-type:
11277     (write-buffered *(ebp+0x10) "fn ")
11278     8b/-> *(ebp+0xc) 0/r32/eax
11279     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11280     (write-buffered *(ebp+0x10) %eax)
11281     (write-buffered *(ebp+0x10) ": stmt get: wrong output type for member '")
11282     (write-buffered *(ebp+0x10) %ecx)
11283     (write-buffered *(ebp+0x10) "' of type '")
11284     bf/copy-to-edi Type-id/imm32
11285     (write-buffered *(ebp+0x10) *(edi+ebx<<2+0xc))
11286     (write-buffered *(ebp+0x10) "'\n")
11287     (flush *(ebp+0x10))
11288     (stop *(ebp+0x14) 1)
11289     # never gets here
11290 
11291 check-mu-index-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11292     # . prologue
11293     55/push-ebp
11294     89/<- %ebp 4/r32/esp
11295     # . save registers
11296 $check-mu-index-stmt:end:
11297     # . restore registers
11298     # . epilogue
11299     89/<- %esp 5/r32/ebp
11300     5d/pop-to-ebp
11301     c3/return
11302 
11303 check-mu-length-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11304     # . prologue
11305     55/push-ebp
11306     89/<- %ebp 4/r32/esp
11307     # . save registers
11308 $check-mu-length-stmt:end:
11309     # . restore registers
11310     # . epilogue
11311     89/<- %esp 5/r32/ebp
11312     5d/pop-to-ebp
11313     c3/return
11314 
11315 check-mu-compute-offset-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11316     # . prologue
11317     55/push-ebp
11318     89/<- %ebp 4/r32/esp
11319     # . save registers
11320 $check-mu-compute-offset-stmt:end:
11321     # . restore registers
11322     # . epilogue
11323     89/<- %esp 5/r32/ebp
11324     5d/pop-to-ebp
11325     c3/return
11326 
11327 check-mu-lookup-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11328     # . prologue
11329     55/push-ebp
11330     89/<- %ebp 4/r32/esp
11331     # . save registers
11332 $check-mu-lookup-stmt:end:
11333     # . restore registers
11334     # . epilogue
11335     89/<- %esp 5/r32/ebp
11336     5d/pop-to-ebp
11337     c3/return
11338 
11339 check-mu-call:  # stmt: (addr stmt), callee: (addr function), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11340     # . prologue
11341     55/push-ebp
11342     89/<- %ebp 4/r32/esp
11343     # . save registers
11344     50/push-eax
11345     51/push-ecx
11346     52/push-edx
11347     53/push-ebx
11348     56/push-esi
11349     57/push-edi
11350     # esi = stmt
11351     8b/-> *(ebp+8) 6/r32/esi
11352     # edi = callee
11353     8b/-> *(ebp+0xc) 7/r32/edi
11354     # var inouts/ecx: (addr stmt-var) = lookup(stmt->inouts)
11355     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11356     89/<- %ecx 0/r32/eax
11357     # var expected/edx: (addr list var) = lookup(f->inouts)
11358     (lookup *(edi+8) *(edi+0xc))  # Function-inouts Function-inouts => eax
11359     89/<- %edx 0/r32/eax
11360     {
11361 $check-mu-call:check-for-inouts:
11362       # if (inouts == 0) break
11363       81 7/subop/compare %ecx 0/imm32
11364       0f 84/jump-if-= break/disp32
11365       # if (expected == 0) error
11366       81 7/subop/compare %edx 0/imm32
11367       0f 84/jump-if-= break/disp32
11368 $check-mu-call:check-inout-type:
11369       # var v/eax: (addr v) = lookup(inouts->value)
11370       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
11371       # var t/ebx: (addr tree type-id) = lookup(v->type)
11372       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11373       89/<- %ebx 0/r32/eax
11374       # if (inouts->is-deref?) t = t->right  # TODO: check that t->left is an addr
11375       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
11376       {
11377         74/jump-if-= break/disp8
11378         (lookup *(ebx+0xc) *(ebx+0x10))  # Tree-right Tree-right => eax
11379         89/<- %ebx 0/r32/eax
11380         # if t->right is null, t = t->left
11381         81 7/subop/compare *(ebx+0xc) 0/imm32  # Tree-right
11382         75/jump-if-!= break/disp8
11383         (lookup *(ebx+4) *(ebx+8))  # Tree-left Tree-left => eax
11384         89/<- %ebx 0/r32/eax
11385       }
11386       # var v2/eax: (addr v) = lookup(expected->value)
11387       (lookup *edx *(edx+4))  # List-value List-value => eax
11388       # var t2/eax: (addr tree type-id) = lookup(v2->type)
11389       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11390       # if (t != t2) error
11391       (type-match? %eax %ebx)  # => eax
11392       3d/compare-eax-and 0/imm32/false
11393       {
11394         0f 85/jump-if-!= break/disp32
11395         (write-buffered *(ebp+0x14) "fn ")
11396         8b/-> *(ebp+0x10) 0/r32/eax
11397         (lookup *eax *(eax+4))  # Function-name Function-name => eax
11398         (write-buffered *(ebp+0x14) %eax)
11399         (write-buffered *(ebp+0x14) ": call ")
11400         (lookup *edi *(edi+4))  # Function-name Function-name => eax
11401         (write-buffered *(ebp+0x14) %eax)
11402         (write-buffered *(ebp+0x14) ": type for inout '")
11403         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
11404         (lookup *eax *(eax+4))  # Var-name Var-name => eax
11405         (write-buffered *(ebp+0x14) %eax)
11406         (write-buffered *(ebp+0x14) "' is not right\n")
11407         (flush *(ebp+0x14))
11408         (stop *(ebp+0x18) 1)
11409       }
11410 $check-mu-call:continue-to-next-inout:
11411       # inouts = lookup(inouts->next)
11412       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
11413       89/<- %ecx 0/r32/eax
11414       # expected = lookup(expected->next)
11415       (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
11416       89/<- %edx 0/r32/eax
11417       #
11418       e9/jump loop/disp32
11419     }
11420 $check-mu-call:check-inout-count:
11421     # if (inouts == expected) proceed
11422     39/compare %ecx 2/r32/edx
11423     {
11424       0f 84/jump-if-= break/disp32
11425       # exactly one of the two is null
11426       # if (inouts == 0) error("too many inouts")
11427       {
11428         81 7/subop/compare %ecx 0/imm32
11429         0f 84/jump-if-= break/disp32
11430         (write-buffered *(ebp+0x14) "fn ")
11431         8b/-> *(ebp+0x10) 0/r32/eax
11432         (lookup *eax *(eax+4))  # Function-name Function-name => eax
11433         (write-buffered *(ebp+0x14) %eax)
11434         (write-buffered *(ebp+0x14) ": call ")
11435         (lookup *edi *(edi+4))  # Function-name Function-name => eax
11436         (write-buffered *(ebp+0x14) %eax)
11437         (write-buffered *(ebp+0x14) ": too many inouts\n")
11438         (flush *(ebp+0x14))
11439         (stop *(ebp+0x18) 1)
11440       }
11441       # if (expected == 0) error("too few inouts")
11442       {
11443         81 7/subop/compare %edx 0/imm32
11444         0f 84/jump-if-= break/disp32
11445         (write-buffered *(ebp+0x14) "fn ")
11446         8b/-> *(ebp+0x10) 0/r32/eax
11447         (lookup *eax *(eax+4))  # Function-name Function-name => eax
11448         (write-buffered *(ebp+0x14) %eax)
11449         (write-buffered *(ebp+0x14) ": call ")
11450         (lookup *edi *(edi+4))  # Function-name Function-name => eax
11451         (write-buffered *(ebp+0x14) %eax)
11452         (write-buffered *(ebp+0x14) ": too few inouts\n")
11453         (flush *(ebp+0x14))
11454         (stop *(ebp+0x18) 1)
11455       }
11456     }
11457 $check-mu-call:check-outputs:
11458     # var outputs/ecx: (addr stmt-var) = lookup(stmt->outputs)
11459     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
11460     89/<- %ecx 0/r32/eax
11461     # var expected/edx: (addr list var) = lookup(f->outputs)
11462     (lookup *(edi+0x10) *(edi+0x14))  # Function-outputs Function-outputs => eax
11463     89/<- %edx 0/r32/eax
11464     {
11465 $check-mu-call:check-for-outputs:
11466       # if (outputs == 0) break
11467       81 7/subop/compare %ecx 0/imm32
11468       0f 84/jump-if-= break/disp32
11469       # if (expected == 0) error
11470       81 7/subop/compare %edx 0/imm32
11471       0f 84/jump-if-= break/disp32
11472 $check-mu-call:check-output-type:
11473       # var v/eax: (addr v) = lookup(outputs->value)
11474       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
11475       # var t/ebx: (addr tree type-id) = lookup(v->type)
11476       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11477       89/<- %ebx 0/r32/eax
11478       # if (outputs->is-deref?) t = t->right  # TODO: check that t->left is an addr
11479       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
11480       {
11481         74/jump-if-= break/disp8
11482         (lookup *(ebx+0xc) *(ebx+0x10))  # Tree-right Tree-right => eax
11483         89/<- %ebx 0/r32/eax
11484       }
11485       # var v2/eax: (addr v) = lookup(expected->value)
11486       (lookup *edx *(edx+4))  # List-value List-value => eax
11487       # var t2/eax: (addr tree type-id) = lookup(v2->type)
11488       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11489       # if (t != t2) error
11490       (type-equal? %eax %ebx)  # => eax
11491       3d/compare-eax-and 0/imm32/false
11492       {
11493         0f 85/jump-if-!= break/disp32
11494         (write-buffered *(ebp+0x14) "fn ")
11495         8b/-> *(ebp+0x10) 0/r32/eax
11496         (lookup *eax *(eax+4))  # Function-name Function-name => eax
11497         (write-buffered *(ebp+0x14) %eax)
11498         (write-buffered *(ebp+0x14) ": call ")
11499         (lookup *edi *(edi+4))  # Function-name Function-name => eax
11500         (write-buffered *(ebp+0x14) %eax)
11501         (write-buffered *(ebp+0x14) ": type for output '")
11502         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
11503         (lookup *eax *(eax+4))  # Var-name Var-name => eax
11504         (write-buffered *(ebp+0x14) %eax)
11505         (write-buffered *(ebp+0x14) "' is not right\n")
11506         (flush *(ebp+0x14))
11507         (stop *(ebp+0x18) 1)
11508       }
11509 $check-mu-call:check-output-register:
11510       # var v/eax: (addr v) = lookup(outputs->value)
11511       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
11512       # var r/ebx: (addr array byte) = lookup(v->register)
11513       (lookup *(eax+18) *(eax+0x1c))  # Var-register Var-register => eax
11514       89/<- %ebx 0/r32/eax
11515       # var v2/eax: (addr v) = lookup(expected->value)
11516       (lookup *edx *(edx+4))  # Stmt-var-value Stmt-var-value => eax
11517       # var r2/eax: (addr array byte) = lookup(v2->register)
11518       (lookup *(eax+18) *(eax+0x1c))  # Var-register Var-register => eax
11519       # if (r != r2) error
11520       (string-equal? %eax %ebx)  # => eax
11521       3d/compare-eax-and 0/imm32/false
11522       {
11523         0f 85/jump-if-!= break/disp32
11524         (write-buffered *(ebp+0x14) "fn ")
11525         8b/-> *(ebp+0x10) 0/r32/eax
11526         (lookup *eax *(eax+4))  # Function-name Function-name => eax
11527         (write-buffered *(ebp+0x14) %eax)
11528         (write-buffered *(ebp+0x14) ": call ")
11529         (lookup *edi *(edi+4))  # Function-name Function-name => eax
11530         (write-buffered *(ebp+0x14) %eax)
11531         (write-buffered *(ebp+0x14) ": register for output '")
11532         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
11533         (lookup *eax *(eax+4))  # Var-name Var-name => eax
11534         (write-buffered *(ebp+0x14) %eax)
11535         (write-buffered *(ebp+0x14) "' is not right\n")
11536         (flush *(ebp+0x14))
11537         (stop *(ebp+0x18) 1)
11538       }
11539 $check-mu-call:continue-to-next-output:
11540       # outputs = lookup(outputs->next)
11541       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
11542       89/<- %ecx 0/r32/eax
11543       # expected = lookup(expected->next)
11544       (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
11545       89/<- %edx 0/r32/eax
11546       #
11547       e9/jump loop/disp32
11548     }
11549 $check-mu-call:check-output-count:
11550     # if (outputs == expected) proceed
11551     39/compare %ecx 2/r32/edx
11552     {
11553       0f 84/jump-if-= break/disp32
11554       # exactly one of the two is null
11555       # if (outputs == 0) error("too many outputs")
11556       {
11557         81 7/subop/compare %ecx 0/imm32
11558         0f 84/jump-if-= break/disp32
11559         (write-buffered *(ebp+0x14) "fn ")
11560         8b/-> *(ebp+0x10) 0/r32/eax
11561         (lookup *eax *(eax+4))  # Function-name Function-name => eax
11562         (write-buffered *(ebp+0x14) %eax)
11563         (write-buffered *(ebp+0x14) ": call ")
11564         (lookup *edi *(edi+4))  # Function-name Function-name => eax
11565         (write-buffered *(ebp+0x14) %eax)
11566         (write-buffered *(ebp+0x14) ": too many outputs\n")
11567         (flush *(ebp+0x14))
11568         (stop *(ebp+0x18) 1)
11569       }
11570       # if (expected == 0) error("too few outputs")
11571       {
11572         81 7/subop/compare %edx 0/imm32
11573         0f 84/jump-if-= break/disp32
11574         (write-buffered *(ebp+0x14) "fn ")
11575         8b/-> *(ebp+0x10) 0/r32/eax
11576         (lookup *eax *(eax+4))  # Function-name Function-name => eax
11577         (write-buffered *(ebp+0x14) %eax)
11578         (write-buffered *(ebp+0x14) ": call ")
11579         (lookup *edi *(edi+4))  # Function-name Function-name => eax
11580         (write-buffered *(ebp+0x14) %eax)
11581         (write-buffered *(ebp+0x14) ": too few outputs\n")
11582         (flush *(ebp+0x14))
11583         (stop *(ebp+0x18) 1)
11584       }
11585     }
11586 $check-mu-call:end:
11587     # . restore registers
11588     5f/pop-to-edi
11589     5e/pop-to-esi
11590     5b/pop-to-ebx
11591     5a/pop-to-edx
11592     59/pop-to-ecx
11593     58/pop-to-eax
11594     # . epilogue
11595     89/<- %esp 5/r32/ebp
11596     5d/pop-to-ebp
11597     c3/return
11598 
11599 # like type-equal? but takes literals into account
11600 type-match?:  # def: (addr tree type-id), call: (addr tree type-id) -> result/eax: boolean
11601     # . prologue
11602     55/push-ebp
11603     89/<- %ebp 4/r32/esp
11604     # if (call == literal) return true  # TODO: more precise
11605     (is-simple-mu-type? *(ebp+0xc) 0)  # literal => eax
11606     3d/compare-eax-and 0/imm32/false
11607     b8/copy-to-eax 1/imm32/true
11608     75/jump-if-!= $type-match?:end/disp8
11609 $type-match?:baseline:
11610     # otherwise fall back
11611     (type-equal? *(ebp+8) *(ebp+0xc))  # => eax
11612 $type-match?:end:
11613     # . epilogue
11614     89/<- %esp 5/r32/ebp
11615     5d/pop-to-ebp
11616     c3/return
11617 
11618 size-of:  # v: (addr var) -> result/eax: int
11619     # . prologue
11620     55/push-ebp
11621     89/<- %ebp 4/r32/esp
11622     # . save registers
11623     51/push-ecx
11624     # var t/ecx: (addr tree type-id) = lookup(v->type)
11625     8b/-> *(ebp+8) 1/r32/ecx
11626 #?     (write-buffered Stderr "size-of ")
11627 #?     (write-int32-hex-buffered Stderr %ecx)
11628 #?     (write-buffered Stderr Newline)
11629 #?     (write-buffered Stderr "type allocid: ")
11630 #?     (write-int32-hex-buffered Stderr *(ecx+8))
11631 #?     (write-buffered Stderr Newline)
11632 #?     (flush Stderr)
11633     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
11634     89/<- %ecx 0/r32/eax
11635     # if is-mu-array?(t) return size-of-array(t)
11636     {
11637       (is-mu-array? %ecx)  # => eax
11638       3d/compare-eax-and 0/imm32/false
11639       74/jump-if-= break/disp8
11640       (size-of-array %ecx)  # => eax
11641       eb/jump $size-of:end/disp8
11642     }
11643     # if (!t->is-atom?) t = lookup(t->left)
11644     {
11645       81 7/subop/compare *ecx 0/imm32/false  # Tree-is-atom
11646       75/jump-if-!= break/disp8
11647       (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
11648       89/<- %ecx 0/r32/eax
11649     }
11650     # TODO: assert t->is-atom?
11651     (size-of-type-id *(ecx+4))  # Tree-value => eax
11652 $size-of:end:
11653     # . restore registers
11654     59/pop-to-ecx
11655     # . epilogue
11656     89/<- %esp 5/r32/ebp
11657     5d/pop-to-ebp
11658     c3/return
11659 
11660 size-of-deref:  # v: (addr var) -> result/eax: int
11661     # . prologue
11662     55/push-ebp
11663     89/<- %ebp 4/r32/esp
11664     # . save registers
11665     51/push-ecx
11666     # var t/ecx: (addr tree type-id) = lookup(v->type)
11667     8b/-> *(ebp+8) 1/r32/ecx
11668     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
11669     89/<- %ecx 0/r32/eax
11670     # TODO: assert(t is an addr)
11671     # t = lookup(t->right)
11672     (lookup *(ecx+0xc) *(ecx+0x10))  # Tree-right Tree-right => eax
11673     89/<- %ecx 0/r32/eax
11674     # if is-mu-array?(t) return size-of-array(t)
11675     {
11676       (is-mu-array? %ecx)  # => eax
11677       3d/compare-eax-and 0/imm32/false
11678       74/jump-if-= break/disp8
11679       (size-of-array %ecx)  # => eax
11680       eb/jump $size-of:end/disp8
11681     }
11682     # if (!t->is-atom?) t = lookup(t->left)
11683     {
11684       81 7/subop/compare *ecx 0/imm32/false  # Tree-is-atom
11685       75/jump-if-!= break/disp8
11686       (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
11687       89/<- %ecx 0/r32/eax
11688     }
11689     # TODO: assert t->is-atom?
11690     (size-of-type-id *(ecx+4))  # Tree-value => eax
11691 $size-of-deref:end:
11692     # . restore registers
11693     59/pop-to-ecx
11694     # . epilogue
11695     89/<- %esp 5/r32/ebp
11696     5d/pop-to-ebp
11697     c3/return
11698 
11699 is-mu-array?:  # t: (addr tree type-id) -> result/eax: boolean
11700     # . prologue
11701     55/push-ebp
11702     89/<- %ebp 4/r32/esp
11703     # . save registers
11704     51/push-ecx
11705     # ecx = t
11706     8b/-> *(ebp+8) 1/r32/ecx
11707     # if t->is-atom?, return false
11708     81 7/subop/compare *ecx 0/imm32/false  # Tree-is-atom
11709     75/jump-if-!= $is-mu-array?:return-false/disp8
11710     # if !t->left->is-atom?, return false
11711     (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
11712     81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
11713     74/jump-if-= $is-mu-array?:return-false/disp8
11714     # return t->left->value == array
11715     81 7/subop/compare *(eax+4) 3/imm32/array-type-id  # Tree-value
11716     0f 94/set-if-= %al
11717     81 4/subop/and %eax 0xff/imm32
11718     eb/jump $is-mu-array?:end/disp8
11719 $is-mu-array?:return-false:
11720     b8/copy-to-eax 0/imm32/false
11721 $is-mu-array?:end:
11722     # . restore registers
11723     59/pop-to-ecx
11724     # . epilogue
11725     89/<- %esp 5/r32/ebp
11726     5d/pop-to-ebp
11727     c3/return
11728 
11729 size-of-array:  # a: (addr tree type-id) -> result/eax: int
11730     # . prologue
11731     55/push-ebp
11732     89/<- %ebp 4/r32/esp
11733     # . save registers
11734     51/push-ecx
11735     52/push-edx
11736     #
11737     8b/-> *(ebp+8) 1/r32/ecx
11738     # TODO: assert that a->left is 'array'
11739     (lookup *(ecx+0xc) *(ecx+0x10))  # Tree-right Tree-right => eax
11740     89/<- %ecx 0/r32/eax
11741     # var elem-type/edx: type-id = a->right->left->value
11742     (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
11743     8b/-> *(eax+4) 2/r32/edx  # Tree-value
11744     # var array-size/ecx: int = a->right->right->left->value
11745     (lookup *(ecx+0xc) *(ecx+0x10))  # Tree-right Tree-right => eax
11746     (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
11747     8b/-> *(eax+4) 1/r32/ecx  # Tree-value
11748     # return array-size * size-of(elem-type)
11749     (size-of-type-id-as-array-element %edx)  # => eax
11750     f7 4/subop/multiply-into-eax %ecx
11751     05/add-to-eax 4/imm32  # for array size
11752 $size-of-array:end:
11753     # . restore registers
11754     5a/pop-to-edx
11755     59/pop-to-ecx
11756     # . epilogue
11757     89/<- %esp 5/r32/ebp
11758     5d/pop-to-ebp
11759     c3/return
11760 
11761 size-of-type-id:  # t: type-id -> result/eax: int
11762     # . prologue
11763     55/push-ebp
11764     89/<- %ebp 4/r32/esp
11765     # . save registers
11766     51/push-ecx
11767     # var out/ecx: (handle typeinfo)
11768     68/push 0/imm32
11769     68/push 0/imm32
11770     89/<- %ecx 4/r32/esp
11771     # eax = t
11772     8b/-> *(ebp+8) 0/r32/eax
11773     # if t is a literal, return 0
11774     3d/compare-eax-and 0/imm32
11775     0f 84/jump-if-= $size-of-type-id:end/disp32  # eax changes type from type-id to int
11776     # if t is a byte, return 4 (because we don't really support non-multiples of 4)
11777     3d/compare-eax-and 8/imm32/byte
11778     {
11779       75/jump-if-!= break/disp8
11780       b8/copy-to-eax 4/imm32
11781       eb/jump $size-of-type-id:end/disp8
11782     }
11783     # if t is a handle, return 8
11784     3d/compare-eax-and 4/imm32/handle
11785     {
11786       75/jump-if-!= break/disp8
11787       b8/copy-to-eax 8/imm32
11788       eb/jump $size-of-type-id:end/disp8  # eax changes type from type-id to int
11789     }
11790     # if t is a user-defined type, return its size
11791     # TODO: support non-atom type
11792     (find-typeinfo %eax %ecx)
11793     {
11794       81 7/subop/compare *ecx 0/imm32
11795       74/jump-if-= break/disp8
11796 $size-of-type-id:user-defined:
11797       (lookup *ecx *(ecx+4))  # => eax
11798       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
11799       eb/jump $size-of-type-id:end/disp8
11800     }
11801     # otherwise return the word size
11802     b8/copy-to-eax 4/imm32
11803 $size-of-type-id:end:
11804     # . reclaim locals
11805     81 0/subop/add %esp 8/imm32
11806     # . restore registers
11807     59/pop-to-ecx
11808     # . epilogue
11809     89/<- %esp 5/r32/ebp
11810     5d/pop-to-ebp
11811     c3/return
11812 
11813 type-equal?:  # a: (addr tree type-id), b: (addr tree type-id) -> result/eax: boolean
11814     # . prologue
11815     55/push-ebp
11816     89/<- %ebp 4/r32/esp
11817     # . save registers
11818     51/push-ecx
11819     52/push-edx
11820     53/push-ebx
11821     # ecx = a
11822     8b/-> *(ebp+8) 1/r32/ecx
11823     # edx = b
11824     8b/-> *(ebp+0xc) 2/r32/edx
11825 $type-equal?:compare-addr:
11826     # if (a == b) return true
11827     8b/-> %ecx 0/r32/eax  # Var-type
11828     39/compare %edx 0/r32/eax  # Var-type
11829     b8/copy-to-eax 1/imm32/true
11830     0f 84/jump-if-= $type-equal?:end/disp32
11831 $type-equal?:compare-atom-state:
11832     # if (a->is-atom? != b->is-atom?) return false
11833     8b/-> *ecx 3/r32/ebx  # Tree-value
11834     39/compare *edx 3/r32/ebx  # Tree-value
11835     b8/copy-to-eax 0/imm32/false
11836     0f 85/jump-if-!= $type-equal?:end/disp32
11837     # if a->is-atom? return (a->value == b->value)
11838     {
11839 $type-equal?:check-atom:
11840       81 7/subop/compare %ebx 0/imm32/false
11841       74/jump-if-= break/disp8
11842 $type-equal?:is-atom:
11843       8b/-> *(ecx+4) 0/r32/eax  # Tree-value
11844       39/compare *(edx+4) 0/r32/eax  # Tree-value
11845       0f 94/set-if-= %al
11846       81 4/subop/and %eax 0xff/imm32
11847       e9/jump $type-equal?:end/disp32
11848     }
11849 $type-equal?:check-left:
11850     # if (!type-equal?(a->left, b->left)) return false
11851     (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
11852     89/<- %ebx 0/r32/eax
11853     (lookup *(edx+4) *(edx+8))  # Tree-left Tree-left => eax
11854     (type-equal? %eax %ebx)  # => eax
11855     3d/compare-eax-and 0/imm32/false
11856     74/jump-if-= $type-equal?:end/disp8
11857 $type-equal?:check-right:
11858     # return type-equal?(a->right, b->right)
11859     (lookup *(ecx+0xc) *(ecx+0x10))  # Tree-right Tree-right => eax
11860     89/<- %ebx 0/r32/eax
11861     (lookup *(edx+0xc) *(edx+0x10))  # Tree-right Tree-right => eax
11862     (type-equal? %eax %ebx)  # => eax
11863 $type-equal?:end:
11864     # . restore registers
11865     5b/pop-to-ebx
11866     5a/pop-to-edx
11867     59/pop-to-ecx
11868     # . epilogue
11869     89/<- %esp 5/r32/ebp
11870     5d/pop-to-ebp
11871     c3/return
11872 
11873 #######################################################
11874 # Code-generation
11875 #######################################################
11876 
11877 == data
11878 
11879 # Global state added to each var record when performing code-generation.
11880 Curr-local-stack-offset:  # (addr int)
11881     0/imm32
11882 
11883 == code
11884 
11885 emit-subx:  # out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
11886     # . prologue
11887     55/push-ebp
11888     89/<- %ebp 4/r32/esp
11889     # . save registers
11890     50/push-eax
11891     # var curr/eax: (addr function) = *Program->functions
11892     (lookup *_Program-functions *_Program-functions->payload)  # => eax
11893     {
11894       # if (curr == null) break
11895       3d/compare-eax-and 0/imm32
11896       0f 84/jump-if-= break/disp32
11897       (emit-subx-function *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))
11898       # curr = lookup(curr->next)
11899       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
11900       e9/jump loop/disp32
11901     }
11902 $emit-subx:end:
11903     # . restore registers
11904     58/pop-to-eax
11905     # . epilogue
11906     89/<- %esp 5/r32/ebp
11907     5d/pop-to-ebp
11908     c3/return
11909 
11910 emit-subx-function:  # out: (addr buffered-file), f: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11911     # . prologue
11912     55/push-ebp
11913     89/<- %ebp 4/r32/esp
11914     # some preprocessing
11915     (populate-mu-type-offsets-in-inouts *(ebp+0xc))
11916     # . save registers
11917     50/push-eax
11918     51/push-ecx
11919     52/push-edx
11920     # initialize some global state
11921     c7 0/subop/copy *Curr-block-depth 1/imm32  # Important: keep this in sync with the parse phase
11922     c7 0/subop/copy *Curr-local-stack-offset 0/imm32
11923     # ecx = f
11924     8b/-> *(ebp+0xc) 1/r32/ecx
11925     # var vars/edx: (stack (addr var) 256)
11926     81 5/subop/subtract %esp 0xc00/imm32
11927     68/push 0xc00/imm32/size
11928     68/push 0/imm32/top
11929     89/<- %edx 4/r32/esp
11930     # var name/eax: (addr array byte) = lookup(f->name)
11931     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
11932     #
11933     (write-buffered *(ebp+8) %eax)
11934     (write-buffered *(ebp+8) ":\n")
11935     (emit-subx-prologue *(ebp+8))
11936     # var body/eax: (addr block) = lookup(f->body)
11937     (lookup *(ecx+0x18) *(ecx+0x1c))  # Function-body Function-body => eax
11938     #
11939     (emit-subx-block *(ebp+8) %eax %edx *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11940     (emit-subx-epilogue *(ebp+8))
11941     # TODO: validate that *Curr-block-depth and *Curr-local-stack-offset have
11942     # been cleaned up
11943 $emit-subx-function:end:
11944     # . reclaim locals
11945     81 0/subop/add %esp 0xc08/imm32
11946     # . restore registers
11947     5a/pop-to-edx
11948     59/pop-to-ecx
11949     58/pop-to-eax
11950     # . epilogue
11951     89/<- %esp 5/r32/ebp
11952     5d/pop-to-ebp
11953     c3/return
11954 
11955 populate-mu-type-offsets-in-inouts:  # f: (addr function)
11956     # . prologue
11957     55/push-ebp
11958     89/<- %ebp 4/r32/esp
11959     # . save registers
11960     50/push-eax
11961     51/push-ecx
11962     52/push-edx
11963     53/push-ebx
11964     57/push-edi
11965     # var next-offset/edx: int = 8
11966     ba/copy-to-edx 8/imm32
11967     # var curr/ecx: (addr list var) = lookup(f->inouts)
11968     8b/-> *(ebp+8) 1/r32/ecx
11969     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
11970     89/<- %ecx 0/r32/eax
11971     {
11972 $populate-mu-type-offsets-in-inouts:loop:
11973       81 7/subop/compare %ecx 0/imm32
11974       74/jump-if-= break/disp8
11975       # var v/ebx: (addr var) = lookup(curr->value)
11976       (lookup *ecx *(ecx+4))  # List-value List-value => eax
11977       89/<- %ebx 0/r32/eax
11978 #?       (lookup *ebx *(ebx+4))
11979 #?       (write-buffered Stderr "setting offset of fn inout ")
11980 #?       (write-buffered Stderr %eax)
11981 #?       (write-buffered Stderr "@")
11982 #?       (write-int32-hex-buffered Stderr %ebx)
11983 #?       (write-buffered Stderr " to ")
11984 #?       (write-int32-hex-buffered Stderr %edx)
11985 #?       (write-buffered Stderr Newline)
11986 #?       (flush Stderr)
11987       # v->offset = next-offset
11988       89/<- *(ebx+0x14) 2/r32/edx  # Var-offset
11989       # next-offset += size-of(v)
11990       (size-of %ebx)  # => eax
11991       01/add-to %edx 0/r32/eax
11992       # curr = lookup(curr->next)
11993       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
11994       89/<- %ecx 0/r32/eax
11995       #
11996       eb/jump loop/disp8
11997     }
11998 $populate-mu-type-offsets-in-inouts:end:
11999     # . restore registers
12000     5f/pop-to-edi
12001     5b/pop-to-ebx
12002     5a/pop-to-edx
12003     59/pop-to-ecx
12004     58/pop-to-eax
12005     # . epilogue
12006     89/<- %esp 5/r32/ebp
12007     5d/pop-to-ebp
12008     c3/return
12009 
12010 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)
12011     # . prologue
12012     55/push-ebp
12013     89/<- %ebp 4/r32/esp
12014     # . save registers
12015     50/push-eax
12016     51/push-ecx
12017     53/push-ebx
12018     56/push-esi
12019     # esi = stmts
12020     8b/-> *(ebp+0xc) 6/r32/esi
12021     #
12022     {
12023 $emit-subx-stmt-list:loop:
12024       81 7/subop/compare %esi 0/imm32
12025       0f 84/jump-if-= break/disp32
12026       # var curr-stmt/ecx: (addr stmt) = lookup(stmts->value)
12027       (lookup *esi *(esi+4))  # List-value List-value => eax
12028       89/<- %ecx 0/r32/eax
12029       {
12030 $emit-subx-stmt-list:check-for-block:
12031         81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
12032         75/jump-if-!= break/disp8
12033 $emit-subx-stmt-list:block:
12034         (emit-subx-block *(ebp+8) %ecx *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
12035       }
12036       {
12037 $emit-subx-stmt-list:check-for-stmt:
12038         81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
12039         0f 85/jump-if-!= break/disp32
12040 $emit-subx-stmt-list:stmt1:
12041         {
12042           (is-mu-branch? %ecx)  # => eax
12043           3d/compare-eax-and 0/imm32/false
12044           0f 84/jump-if-= break/disp32
12045 $emit-subx-stmt-list:branch-stmt:
12046 +-- 27 lines: # unconditional loops -----------------------------------------------------------------------------------------------------------------------------------------------------
12073 +-- 16 lines: # unconditional breaks ----------------------------------------------------------------------------------------------------------------------------------------------------
12089 +-- 38 lines: # simple conditional branches without a target ----------------------------------------------------------------------------------------------------------------------------
12127 +-- 19 lines: # conditional branches with an explicit target ----------------------------------------------------------------------------------------------------------------------------
12146         }
12147 $emit-subx-stmt-list:1-to-1:
12148         (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x18) *(ebp+0x1c))
12149         e9/jump $emit-subx-stmt-list:continue/disp32
12150       }
12151       {
12152 $emit-subx-stmt-list:check-for-var-def:
12153         81 7/subop/compare *ecx 2/imm32/var-def  # Stmt-tag
12154         75/jump-if-!= break/disp8
12155 $emit-subx-stmt-list:var-def:
12156         (emit-subx-var-def *(ebp+8) %ecx)
12157         (push *(ebp+0x10) *(ecx+4))  # Vardef-var
12158         (push *(ebp+0x10) *(ecx+8))  # Vardef-var
12159         (push *(ebp+0x10) 0)  # Live-var-register-spilled = 0 for vars on the stack
12160         #
12161         eb/jump $emit-subx-stmt-list:continue/disp8
12162       }
12163       {
12164 $emit-subx-stmt-list:check-for-reg-var-def:
12165         81 7/subop/compare *ecx 3/imm32/reg-var-def  # Stmt-tag
12166         0f 85/jump-if-!= break/disp32
12167 $emit-subx-stmt-list:reg-var-def:
12168         # TODO: ensure that there's exactly one output
12169         (push-output-and-maybe-emit-spill *(ebp+8) %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
12170         # emit the instruction as usual
12171         (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x18) *(ebp+0x1c))
12172         #
12173         eb/jump $emit-subx-stmt-list:continue/disp8
12174       }
12175 $emit-subx-stmt-list:continue:
12176       # TODO: raise an error on unrecognized Stmt-tag
12177       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
12178       89/<- %esi 0/r32/eax
12179       e9/jump loop/disp32
12180     }
12181 $emit-subx-stmt-list:emit-cleanup:
12182     (emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth)
12183 $emit-subx-stmt-list:clean-up:
12184     (clean-up-blocks *(ebp+0x10) *Curr-block-depth *(ebp+0x14))
12185 $emit-subx-stmt-list:end:
12186     # . restore registers
12187     5e/pop-to-esi
12188     5b/pop-to-ebx
12189     59/pop-to-ecx
12190     58/pop-to-eax
12191     # . epilogue
12192     89/<- %esp 5/r32/ebp
12193     5d/pop-to-ebp
12194     c3/return
12195 
12196 # 'later-stmts' includes 'stmt', but will behave the same even without it; reg-var-def stmts are guaranteed not to write to function outputs.
12197 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)
12198     # . prologue
12199     55/push-ebp
12200     89/<- %ebp 4/r32/esp
12201     # . save registers
12202     50/push-eax
12203     51/push-ecx
12204     52/push-edx
12205     # ecx = stmt
12206     8b/-> *(ebp+0xc) 1/r32/ecx
12207     # var sv/eax: (addr stmt-var) = lookup(curr-stmt->outputs)
12208     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
12209     # TODO: assert !sv->is-deref?
12210     # var v/ecx: (addr var) = lookup(sv->value)
12211     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12212     89/<- %ecx 0/r32/eax
12213     # v->block-depth = *Curr-block-depth
12214     8b/-> *Curr-block-depth 0/r32/eax
12215     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
12216 #?     (write-buffered Stderr "var ")
12217 #?     (lookup *ecx *(ecx+4))
12218 #?     (write-buffered Stderr %eax)
12219 #?     (write-buffered Stderr " at depth ")
12220 #?     (write-int32-hex-buffered Stderr *(ecx+0x10))
12221 #?     (write-buffered Stderr Newline)
12222 #?     (flush Stderr)
12223     # ensure that v is in a register
12224     81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
12225     0f 84/jump-if-= $push-output-and-maybe-emit-spill:abort/disp32
12226     # var emit-spill?/edx: boolean = not-yet-spilled-this-block? && will-not-write-some-register?(fn)
12227     (not-yet-spilled-this-block? %ecx *(ebp+0x10))  # => eax
12228     89/<- %edx 0/r32/eax
12229     3d/compare-eax-and 0/imm32/false
12230     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
12231     (will-not-write-some-register? %ecx *(ebp+0x14) *(ebp+0x18))  # => eax
12232     89/<- %edx 0/r32/eax
12233     # check emit-spill?
12234     3d/compare-eax-and 0/imm32/false
12235     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
12236     # TODO: assert(size-of(output) == 4)
12237     # *Curr-local-stack-offset -= 4
12238     81 5/subop/subtract *Curr-local-stack-offset 4/imm32
12239     # emit spill
12240     (emit-indent *(ebp+8) *Curr-block-depth)
12241     (write-buffered *(ebp+8) "ff 6/subop/push %")
12242     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
12243     (write-buffered *(ebp+8) %eax)
12244     (write-buffered *(ebp+8) Newline)
12245 $push-output-and-maybe-emit-spill:push:
12246     8b/-> *(ebp+0xc) 1/r32/ecx
12247     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
12248     # push(vars, {sv->value, emit-spill?})
12249     (push *(ebp+0x10) *eax)  # Stmt-var-value
12250     (push *(ebp+0x10) *(eax+4))  # Stmt-var-value
12251     (push *(ebp+0x10) %edx)
12252 $push-output-and-maybe-emit-spill:end:
12253     # . restore registers
12254     5a/pop-to-edx
12255     59/pop-to-ecx
12256     58/pop-to-eax
12257     # . epilogue
12258     89/<- %esp 5/r32/ebp
12259     5d/pop-to-ebp
12260     c3/return
12261 
12262 $push-output-and-maybe-emit-spill:abort:
12263     # error("var '" var->name "' initialized from an instruction must live in a register\n")
12264     (write-buffered *(ebp+0x1c) "var '")
12265     (write-buffered *(ebp+0x1c) *eax)  # Var-name
12266     (write-buffered *(ebp+0x1c) "' initialized from an instruction must live in a register\n")
12267     (flush *(ebp+0x1c))
12268     (stop *(ebp+0x20) 1)
12269     # never gets here
12270 
12271 emit-subx-cleanup-and-unconditional-nonlocal-branch:  # out: (addr buffered-file), stmt: (addr stmt1), vars: (addr stack live-var)
12272     # . prologue
12273     55/push-ebp
12274     89/<- %ebp 4/r32/esp
12275     # . save registers
12276     50/push-eax
12277     51/push-ecx
12278     # ecx = stmt
12279     8b/-> *(ebp+0xc) 1/r32/ecx
12280     # var target/eax: (addr array byte) = curr-stmt->inouts->value->name
12281     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12282     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12283     (lookup *eax *(eax+4))  # Var-name Var-name => eax
12284     # clean up until target block
12285     (emit-cleanup-code-until-target *(ebp+8) *(ebp+0x10) %eax)
12286     # emit jump to target block
12287     (emit-indent *(ebp+8) *Curr-block-depth)
12288     (write-buffered *(ebp+8) "e9/jump ")
12289     (write-buffered *(ebp+8) %eax)
12290     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
12291     (string-starts-with? %eax "break")
12292     3d/compare-eax-and 0/imm32/false
12293     {
12294       74/jump-if-= break/disp8
12295       (write-buffered *(ebp+8) ":break/disp32\n")
12296     }
12297     3d/compare-eax-and 0/imm32/false  # just in case the function call modified flags
12298     {
12299       75/jump-if-!= break/disp8
12300       (write-buffered *(ebp+8) ":loop/disp32\n")
12301     }
12302 $emit-subx-cleanup-and-unconditional-nonlocal-branch:end:
12303     # . restore registers
12304     59/pop-to-ecx
12305     58/pop-to-eax
12306     # . epilogue
12307     89/<- %esp 5/r32/ebp
12308     5d/pop-to-ebp
12309     c3/return
12310 
12311 is-mu-branch?:  # stmt: (addr stmt1) -> result/eax: boolean
12312     # . prologue
12313     55/push-ebp
12314     89/<- %ebp 4/r32/esp
12315     # . save registers
12316     51/push-ecx
12317     # ecx = lookup(stmt->operation)
12318     8b/-> *(ebp+8) 1/r32/ecx
12319     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
12320     89/<- %ecx 0/r32/eax
12321     # if (stmt->operation starts with "loop") return true
12322     (string-starts-with? %ecx "loop")  # => eax
12323     3d/compare-eax-and 0/imm32/false
12324     75/jump-if-not-equal $is-mu-branch?:end/disp8
12325     # otherwise return (stmt->operation starts with "break")
12326     (string-starts-with? %ecx "break")  # => eax
12327 $is-mu-branch?:end:
12328     # . restore registers
12329     59/pop-to-ecx
12330     # . epilogue
12331     89/<- %esp 5/r32/ebp
12332     5d/pop-to-ebp
12333     c3/return
12334 
12335 emit-reverse-break:  # out: (addr buffered-file), stmt: (addr stmt1)
12336     # . prologue
12337     55/push-ebp
12338     89/<- %ebp 4/r32/esp
12339     # . save registers
12340     50/push-eax
12341     # eax = stmt
12342     8b/-> *(ebp+0xc) 0/r32/eax
12343     #
12344     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
12345     (get Reverse-branch %eax 0x10 "reverse-branch: ")  # => eax: (addr handle array byte)
12346     (emit-indent *(ebp+8) *Curr-block-depth)
12347     (lookup *eax *(eax+4))  # => eax
12348     (write-buffered *(ebp+8) %eax)
12349     (write-buffered *(ebp+8) " break/disp32\n")
12350 $emit-reverse-break:end:
12351     # . restore registers
12352     58/pop-to-eax
12353     # . epilogue
12354     89/<- %esp 5/r32/ebp
12355     5d/pop-to-ebp
12356     c3/return
12357 
12358 == data
12359 
12360 # Table from Mu branch instructions to the reverse SubX opcodes for them.
12361 Reverse-branch:  # (table (handle array byte) (handle array byte))
12362   # a table is a stream
12363   0x140/imm32/write
12364   0/imm32/read
12365   0x140/imm32/size
12366   # data
12367   0x11/imm32/alloc-id   _string-break-if-=/imm32                0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
12368   0x11/imm32/alloc-id   _string-loop-if-=/imm32                 0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
12369   0x11/imm32/alloc-id   _string-break-if-!=/imm32               0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
12370   0x11/imm32/alloc-id   _string-loop-if-!=/imm32                0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
12371   0x11/imm32/alloc-id   _string-break-if-</imm32                0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
12372   0x11/imm32/alloc-id   _string-loop-if-</imm32                 0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
12373   0x11/imm32/alloc-id   _string-break-if->/imm32                0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
12374   0x11/imm32/alloc-id   _string-loop-if->/imm32                 0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
12375   0x11/imm32/alloc-id   _string-break-if-<=/imm32               0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
12376   0x11/imm32/alloc-id   _string-loop-if-<=/imm32                0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
12377   0x11/imm32/alloc-id   _string-break-if->=/imm32               0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
12378   0x11/imm32/alloc-id   _string-loop-if->=/imm32                0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
12379   0x11/imm32/alloc-id   _string-break-if-addr</imm32            0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
12380   0x11/imm32/alloc-id   _string-loop-if-addr</imm32             0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
12381   0x11/imm32/alloc-id   _string-break-if-addr>/imm32            0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
12382   0x11/imm32/alloc-id   _string-loop-if-addr>/imm32             0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
12383   0x11/imm32/alloc-id   _string-break-if-addr<=/imm32           0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
12384   0x11/imm32/alloc-id   _string-loop-if-addr<=/imm32            0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
12385   0x11/imm32/alloc-id   _string-break-if-addr>=/imm32           0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
12386   0x11/imm32/alloc-id   _string-loop-if-addr>=/imm32            0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
12387 
12388 == code
12389 
12390 emit-unconditional-jump-to-depth:  # out: (addr buffered-file), vars: (addr stack live-var), depth: int, label-suffix: (addr array byte)
12391     # . prologue
12392     55/push-ebp
12393     89/<- %ebp 4/r32/esp
12394     # . save registers
12395     50/push-eax
12396     51/push-ecx
12397     52/push-edx
12398     53/push-ebx
12399     56/push-esi
12400     # ecx = vars
12401     8b/-> *(ebp+0xc) 1/r32/ecx
12402     # var eax: int = vars->top
12403     8b/-> *ecx 0/r32/eax
12404     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
12405     8d/copy-address *(ecx+eax-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
12406     # var min/ecx: (addr handle var) = vars->data
12407     8d/copy-address *(ecx+8) 1/r32/ecx
12408     # edx = depth
12409     8b/-> *(ebp+0x10) 2/r32/edx
12410     {
12411 $emit-unconditional-jump-to-depth:loop:
12412       # if (curr < min) break
12413       39/compare %esi 1/r32/ecx
12414       0f 82/jump-if-addr< break/disp32
12415       # var v/ebx: (addr var) = lookup(*curr)
12416       (lookup *esi *(esi+4))  # => eax
12417       89/<- %ebx 0/r32/eax
12418       # if (v->block-depth < until-block-depth) break
12419       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
12420       0f 8c/jump-if-< break/disp32
12421       {
12422 $emit-unconditional-jump-to-depth:check:
12423         # if v->block-depth != until-block-depth, continue
12424         39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
12425         0f 85/jump-if-!= break/disp32
12426 $emit-unconditional-jump-to-depth:depth-found:
12427         # if v is not a literal, continue
12428         (size-of %ebx)  # => eax
12429         3d/compare-eax-and 0/imm32
12430         0f 85/jump-if-!= break/disp32
12431 $emit-unconditional-jump-to-depth:label-found:
12432         # emit unconditional jump, then return
12433         (emit-indent *(ebp+8) *Curr-block-depth)
12434         (write-buffered *(ebp+8) "e9/jump ")
12435         (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
12436         (write-buffered *(ebp+8) %eax)
12437         (write-buffered *(ebp+8) ":")
12438         (write-buffered *(ebp+8) *(ebp+0x14))
12439         (write-buffered *(ebp+8) "/disp32\n")
12440         eb/jump $emit-unconditional-jump-to-depth:end/disp8
12441       }
12442       # curr -= 12
12443       81 5/subop/subtract %esi 0xc/imm32
12444       e9/jump loop/disp32
12445     }
12446     # TODO: error if no label at 'depth' was found
12447 $emit-unconditional-jump-to-depth:end:
12448     # . restore registers
12449     5e/pop-to-esi
12450     5b/pop-to-ebx
12451     5a/pop-to-edx
12452     59/pop-to-ecx
12453     58/pop-to-eax
12454     # . epilogue
12455     89/<- %esp 5/r32/ebp
12456     5d/pop-to-ebp
12457     c3/return
12458 
12459 # emit clean-up code for 'vars' until some block depth
12460 # doesn't actually modify 'vars' so we need traverse manually inside the stack
12461 emit-cleanup-code-until-depth:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-depth: int
12462     # . prologue
12463     55/push-ebp
12464     89/<- %ebp 4/r32/esp
12465     # . save registers
12466     50/push-eax
12467     51/push-ecx
12468     52/push-edx
12469     53/push-ebx
12470     56/push-esi
12471 #?     (write-buffered Stderr "--- cleanup\n")
12472 #?     (flush Stderr)
12473     # ecx = vars
12474     8b/-> *(ebp+0xc) 1/r32/ecx
12475     # var esi: int = vars->top
12476     8b/-> *ecx 6/r32/esi
12477     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
12478     8d/copy-address *(ecx+esi-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
12479     # var min/ecx: (addr handle var) = vars->data
12480     81 0/subop/add %ecx 8/imm32
12481     # edx = until-block-depth
12482     8b/-> *(ebp+0x10) 2/r32/edx
12483     {
12484 $emit-cleanup-code-until-depth:loop:
12485       # if (curr < min) break
12486       39/compare %esi 1/r32/ecx
12487       0f 82/jump-if-addr< break/disp32
12488       # var v/ebx: (addr var) = lookup(*curr)
12489       (lookup *esi *(esi+4))  # => eax
12490       89/<- %ebx 0/r32/eax
12491 #?       (lookup *ebx *(ebx+4))  # Var-name
12492 #?       (write-buffered Stderr "var ")
12493 #?       (write-buffered Stderr %eax)
12494 #?       (write-buffered Stderr Newline)
12495 #?       (flush Stderr)
12496       # if (v->block-depth < until-block-depth) break
12497       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
12498       0f 8c/jump-if-< break/disp32
12499       # if v is in a register
12500       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
12501       {
12502         0f 84/jump-if-= break/disp32
12503         {
12504 $emit-cleanup-code-until-depth:check-for-previous-spill:
12505           8b/-> *(esi+8) 0/r32/eax  # Live-var-register-spilled
12506           3d/compare-eax-and 0/imm32/false
12507           74/jump-if-= break/disp8
12508 $emit-cleanup-code-until-depth:reclaim-var-in-register:
12509           (emit-indent *(ebp+8) *Curr-block-depth)
12510           (write-buffered *(ebp+8) "8f 0/subop/pop %")
12511           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
12512           (write-buffered *(ebp+8) %eax)
12513           (write-buffered *(ebp+8) Newline)
12514         }
12515         eb/jump $emit-cleanup-code-until-depth:continue/disp8
12516       }
12517       # otherwise v is on the stack
12518       {
12519         75/jump-if-!= break/disp8
12520 $emit-cleanup-code-until-depth:var-on-stack:
12521         (size-of %ebx)  # => eax
12522         # don't emit code for labels
12523         3d/compare-eax-and 0/imm32
12524         74/jump-if-= break/disp8
12525 $emit-cleanup-code-until-depth:reclaim-var-on-stack:
12526         (emit-indent *(ebp+8) *Curr-block-depth)
12527         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
12528         (write-int32-hex-buffered *(ebp+8) %eax)
12529         (write-buffered *(ebp+8) "/imm32\n")
12530       }
12531 $emit-cleanup-code-until-depth:continue:
12532       # curr -= 12
12533       81 5/subop/subtract %esi 0xc/imm32
12534       e9/jump loop/disp32
12535     }
12536 $emit-cleanup-code-until-depth:end:
12537     # . restore registers
12538     5e/pop-to-esi
12539     5b/pop-to-ebx
12540     5a/pop-to-edx
12541     59/pop-to-ecx
12542     58/pop-to-eax
12543     # . epilogue
12544     89/<- %esp 5/r32/ebp
12545     5d/pop-to-ebp
12546     c3/return
12547 
12548 # emit clean-up code for 'vars' until a given label is encountered
12549 # doesn't actually modify 'vars' so we need traverse manually inside the stack
12550 emit-cleanup-code-until-target:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-label: (addr array byte)
12551     # . prologue
12552     55/push-ebp
12553     89/<- %ebp 4/r32/esp
12554     # . save registers
12555     50/push-eax
12556     51/push-ecx
12557     52/push-edx
12558     53/push-ebx
12559     # ecx = vars
12560     8b/-> *(ebp+0xc) 1/r32/ecx
12561     # var eax: int = vars->top
12562     8b/-> *ecx 0/r32/eax
12563     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
12564     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
12565     # var min/ecx: (addr handle var) = vars->data
12566     81 0/subop/add %ecx 8/imm32
12567     {
12568 $emit-cleanup-code-until-target:loop:
12569       # if (curr < min) break
12570       39/compare %edx 1/r32/ecx
12571       0f 82/jump-if-addr< break/disp32
12572       # var v/ebx: (handle var) = lookup(*curr)
12573       (lookup *edx *(edx+4))  # => eax
12574       89/<- %ebx 0/r32/eax
12575       # if (v->name == until-block-label) break
12576       (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
12577       (string-equal? %eax *(ebp+0x10))  # => eax
12578       3d/compare-eax-and 0/imm32/false
12579       0f 85/jump-if-!= break/disp32
12580       # if v is in a register
12581       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
12582       {
12583         0f 84/jump-if-= break/disp32
12584         {
12585 $emit-cleanup-code-until-target:check-for-previous-spill:
12586           8b/-> *(edx+8) 0/r32/eax  # Live-var-register-spilled
12587           3d/compare-eax-and 0/imm32/false
12588           74/jump-if-= break/disp8
12589 $emit-cleanup-code-until-target:reclaim-var-in-register:
12590           (emit-indent *(ebp+8) *Curr-block-depth)
12591           (write-buffered *(ebp+8) "8f 0/subop/pop %")
12592           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
12593           (write-buffered *(ebp+8) %eax)
12594           (write-buffered *(ebp+8) Newline)
12595         }
12596         eb/jump $emit-cleanup-code-until-target:continue/disp8
12597       }
12598       # otherwise v is on the stack
12599       {
12600         75/jump-if-!= break/disp8
12601 $emit-cleanup-code-until-target:reclaim-var-on-stack:
12602         (size-of %ebx)  # => eax
12603         # don't emit code for labels
12604         3d/compare-eax-and 0/imm32
12605         74/jump-if-= break/disp8
12606         #
12607         (emit-indent *(ebp+8) *Curr-block-depth)
12608         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
12609         (write-int32-hex-buffered *(ebp+8) %eax)
12610         (write-buffered *(ebp+8) "/imm32\n")
12611       }
12612 $emit-cleanup-code-until-target:continue:
12613       # curr -= 12
12614       81 5/subop/subtract %edx 0xc/imm32
12615       e9/jump loop/disp32
12616     }
12617 $emit-cleanup-code-until-target:end:
12618     # . restore registers
12619     5b/pop-to-ebx
12620     5a/pop-to-edx
12621     59/pop-to-ecx
12622     58/pop-to-eax
12623     # . epilogue
12624     89/<- %esp 5/r32/ebp
12625     5d/pop-to-ebp
12626     c3/return
12627 
12628 # Return true if there isn't a variable in 'vars' with the same block-depth
12629 # and register as 'v'.
12630 # 'v' is guaranteed not to be within 'vars'.
12631 not-yet-spilled-this-block?:  # v: (addr var), vars: (addr stack live-var) -> result/eax: boolean
12632     # . prologue
12633     55/push-ebp
12634     89/<- %ebp 4/r32/esp
12635     # . save registers
12636     51/push-ecx
12637     52/push-edx
12638     53/push-ebx
12639     56/push-esi
12640     57/push-edi
12641     # ecx = vars
12642     8b/-> *(ebp+0xc) 1/r32/ecx
12643     # var eax: int = vars->top
12644     8b/-> *ecx 0/r32/eax
12645     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
12646     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
12647     # var min/ecx: (addr handle var) = vars->data
12648     8d/copy-address *(ecx+8) 1/r32/ecx
12649     # var depth/ebx: int = v->block-depth
12650     8b/-> *(ebp+8) 3/r32/ebx
12651     8b/-> *(ebx+0x10) 3/r32/ebx  # Var-block-depth
12652     # var needle/esi: (addr array byte) = v->register
12653     8b/-> *(ebp+8) 6/r32/esi
12654     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
12655     89/<- %esi 0/r32/eax
12656     {
12657 $not-yet-spilled-this-block?:loop:
12658       # if (curr < min) break
12659       39/compare %edx 1/r32/ecx
12660       0f 82/jump-if-addr< break/disp32
12661       # var cand/edi: (addr var) = lookup(*curr)
12662       (lookup *edx *(edx+4))  # => eax
12663       89/<- %edi 0/r32/eax
12664       # if (cand->block-depth < depth) break
12665       39/compare *(edi+0x10) 3/r32/ebx  # Var-block-depth
12666       0f 8c/jump-if-< break/disp32
12667       # var cand-reg/edi: (array array byte) = cand->reg
12668       (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
12669       89/<- %edi 0/r32/eax
12670       # if (cand-reg == null) continue
12671       {
12672 $not-yet-spilled-this-block?:check-reg:
12673         81 7/subop/compare %edi 0/imm32
12674         0f 84/jump-if-= break/disp32
12675         # if (cand-reg == needle) return true
12676         (string-equal? %esi %edi)  # => eax
12677         3d/compare-eax-and 0/imm32/false
12678         74/jump-if-= break/disp8
12679 $not-yet-spilled-this-block?:return-false:
12680         b8/copy-to-eax 0/imm32/false
12681         eb/jump $not-yet-spilled-this-block?:end/disp8
12682       }
12683 $not-yet-spilled-this-block?:continue:
12684       # curr -= 12
12685       81 5/subop/subtract %edx 0xc/imm32
12686       e9/jump loop/disp32
12687     }
12688 $not-yet-spilled-this-block?:return-true:
12689     # return true
12690     b8/copy-to-eax 1/imm32/true
12691 $not-yet-spilled-this-block?:end:
12692     # . restore registers
12693     5f/pop-to-edi
12694     5e/pop-to-esi
12695     5b/pop-to-ebx
12696     5a/pop-to-edx
12697     59/pop-to-ecx
12698     # . epilogue
12699     89/<- %esp 5/r32/ebp
12700     5d/pop-to-ebp
12701     c3/return
12702 
12703 # could the register of 'v' ever be written to by one of the vars in fn-outputs?
12704 will-not-write-some-register?:  # v: (addr var), stmts: (addr list stmt), fn: (addr function) -> result/eax: boolean
12705     # . prologue
12706     55/push-ebp
12707     89/<- %ebp 4/r32/esp
12708     # eax = v
12709     8b/-> *(ebp+8) 0/r32/eax
12710     # var reg/eax: (addr array byte) = lookup(v->register)
12711     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
12712     # var target/eax: (addr var) = find-register(fn-outputs, reg)
12713     (find-register *(ebp+0x10) %eax)  # => eax
12714     # if (target == 0) return true
12715     {
12716       3d/compare-eax-and 0/imm32
12717       75/jump-if-!= break/disp8
12718       b8/copy-to-eax 1/imm32/true
12719       eb/jump $will-not-write-some-register?:end/disp8
12720     }
12721     # return !assigns-in-stmts?(stmts, target)
12722     (assigns-in-stmts? *(ebp+0xc) %eax)  # => eax
12723     3d/compare-eax-and 0/imm32/false
12724     # assume: true = 1, so no need to mask with 0x000000ff
12725     0f 94/set-if-= %al
12726 $will-not-write-some-register?:end:
12727     # . epilogue
12728     89/<- %esp 5/r32/ebp
12729     5d/pop-to-ebp
12730     c3/return
12731 
12732 # return fn output with matching register
12733 # always returns false if 'reg' is null
12734 find-register:  # fn: (addr function), reg: (addr array byte) -> result/eax: (addr var)
12735     # . prologue
12736     55/push-ebp
12737     89/<- %ebp 4/r32/esp
12738     # . save registers
12739     51/push-ecx
12740     # var curr/ecx: (addr list var) = lookup(fn->outputs)
12741     8b/-> *(ebp+8) 1/r32/ecx
12742     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
12743     89/<- %ecx 0/r32/eax
12744     {
12745 $find-register:loop:
12746       # if (curr == 0) break
12747       81 7/subop/compare %ecx 0/imm32
12748       74/jump-if-= break/disp8
12749       # eax = curr->value->register
12750       (lookup *ecx *(ecx+4))  # List-value List-value => eax
12751       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
12752       # if (eax == reg) return curr->value
12753 $find-register:compare:
12754       (string-equal? *(ebp+0xc) %eax)  # => eax
12755       {
12756         3d/compare-eax-and 0/imm32/false
12757         74/jump-if-= break/disp8
12758 $find-register:found:
12759         (lookup *ecx *(ecx+4))  # List-value List-value => eax
12760         eb/jump $find-register:end/disp8
12761       }
12762       # curr = lookup(curr->next)
12763       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
12764       89/<- %ecx 0/r32/eax
12765       #
12766       eb/jump loop/disp8
12767     }
12768 $find-register:end:
12769     # . restore registers
12770     59/pop-to-ecx
12771     # . epilogue
12772     89/<- %esp 5/r32/ebp
12773     5d/pop-to-ebp
12774     c3/return
12775 
12776 assigns-in-stmts?:  # stmts: (addr list stmt), v: (addr var) -> result/eax: boolean
12777     # . prologue
12778     55/push-ebp
12779     89/<- %ebp 4/r32/esp
12780     # . save registers
12781     51/push-ecx
12782     # var curr/ecx: (addr list stmt) = stmts
12783     8b/-> *(ebp+8) 1/r32/ecx
12784     {
12785       # if (curr == 0) break
12786       81 7/subop/compare %ecx 0/imm32
12787       74/jump-if-= break/disp8
12788       # if assigns-in-stmt?(curr->value, v) return true
12789       (lookup *ecx *(ecx+4))  # List-value List-value => eax
12790       (assigns-in-stmt? %eax *(ebp+0xc))  # => eax
12791       3d/compare-eax-and 0/imm32/false
12792       75/jump-if-!= break/disp8
12793       # curr = lookup(curr->next)
12794       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
12795       89/<- %ecx 0/r32/eax
12796       #
12797       eb/jump loop/disp8
12798     }
12799 $assigns-in-stmts?:end:
12800     # . restore registers
12801     59/pop-to-ecx
12802     # . epilogue
12803     89/<- %esp 5/r32/ebp
12804     5d/pop-to-ebp
12805     c3/return
12806 
12807 assigns-in-stmt?:  # stmt: (addr stmt), v: (addr var) -> result/eax: boolean
12808     # . prologue
12809     55/push-ebp
12810     89/<- %ebp 4/r32/esp
12811     # . save registers
12812     51/push-ecx
12813     # ecx = stmt
12814     8b/-> *(ebp+8) 1/r32/ecx
12815     # if stmt is a stmt1, return assigns-in-stmt-vars?(stmt->outputs, v)
12816     {
12817       81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
12818       75/jump-if-!= break/disp8
12819       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
12820       (assigns-in-stmt-vars? %eax *(ebp+0xc))  # => eax
12821       eb/jump $assigns-in-stmt?:end/disp8
12822     }
12823     # if stmt is a block, return assigns-in-stmts?(stmt->stmts, v)
12824     {
12825       81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
12826       75/jump-if-!= break/disp8
12827       (lookup *(ecx+4) *(ecx+8))  # Block-stmts Block-stmts => eax
12828       (assigns-in-stmts? %eax *(ebp+0xc))  # => eax
12829       eb/jump $assigns-in-stmt?:end/disp8
12830     }
12831     # otherwise return false
12832     b8/copy 0/imm32/false
12833 $assigns-in-stmt?:end:
12834     # . restore registers
12835     59/pop-to-ecx
12836     # . epilogue
12837     89/<- %esp 5/r32/ebp
12838     5d/pop-to-ebp
12839     c3/return
12840 
12841 assigns-in-stmt-vars?:  # stmt-var: (addr stmt-var), v: (addr var) -> result/eax: boolean
12842     # . prologue
12843     55/push-ebp
12844     89/<- %ebp 4/r32/esp
12845     # . save registers
12846     51/push-ecx
12847     # var curr/ecx: (addr stmt-var) = stmt-var
12848     8b/-> *(ebp+8) 1/r32/ecx
12849     {
12850       # if (curr == 0) break
12851       81 7/subop/compare %ecx 0/imm32
12852       74/jump-if-= break/disp8
12853       # eax = lookup(curr->value)
12854       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12855       # if (eax == v  &&  curr->is-deref? == false) return true
12856       {
12857         39/compare *(ebp+0xc) 0/r32/eax
12858         75/jump-if-!= break/disp8
12859         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
12860         75/jump-if-!= break/disp8
12861         b8/copy-to-eax 1/imm32/true
12862         eb/jump $assigns-in-stmt-vars?:end/disp8
12863       }
12864       # curr = lookup(curr->next)
12865       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
12866       89/<- %ecx 0/r32/eax
12867       #
12868       eb/jump loop/disp8
12869     }
12870 $assigns-in-stmt-vars?:end:
12871     # . restore registers
12872     59/pop-to-ecx
12873     # . epilogue
12874     89/<- %esp 5/r32/ebp
12875     5d/pop-to-ebp
12876     c3/return
12877 
12878 # is there a var before 'v' with the same block-depth and register on the 'vars' stack?
12879 # v is guaranteed to be within vars
12880 # 'start' is provided as an optimization, a pointer within vars
12881 # *start == v
12882 same-register-spilled-before?:  # v: (addr var), vars: (addr stack (handle var)), start: (addr var) -> result/eax: boolean
12883     # . prologue
12884     55/push-ebp
12885     89/<- %ebp 4/r32/esp
12886     # . save registers
12887     51/push-ecx
12888     52/push-edx
12889     53/push-ebx
12890     56/push-esi
12891     57/push-edi
12892     # ecx = v
12893     8b/-> *(ebp+8) 1/r32/ecx
12894     # var reg/edx: (addr array byte) = lookup(v->register)
12895     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
12896     89/<- %edx 0/r32/eax
12897     # var depth/ebx: int = v->block-depth
12898     8b/-> *(ecx+0x10) 3/r32/ebx  # Var-block-depth
12899     # var min/ecx: (addr handle var) = vars->data
12900     8b/-> *(ebp+0xc) 1/r32/ecx
12901     81 0/subop/add %ecx 8/imm32
12902     # TODO: check that start >= min and start < &vars->data[top]
12903     # TODO: check that *start == v
12904     # var curr/esi: (addr handle var) = start
12905     8b/-> *(ebp+0x10) 6/r32/esi
12906     # curr -= 8
12907     81 5/subop/subtract %esi 8/imm32
12908     {
12909 $same-register-spilled-before?:loop:
12910       # if (curr < min) break
12911       39/compare %esi 1/r32/ecx
12912       0f 82/jump-if-addr< break/disp32
12913       # var x/eax: (addr var) = lookup(*curr)
12914       (lookup *esi *(esi+4))  # => eax
12915       # if (x->block-depth < depth) break
12916       39/compare *(eax+0x10) 3/r32/ebx  # Var-block-depth
12917       0f 8c/jump-if-< break/disp32
12918       # if (x->register == 0) continue
12919       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
12920       74/jump-if-= $same-register-spilled-before?:continue/disp8
12921       # if (x->register == reg) return true
12922       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
12923       (string-equal? %eax %edx)  # => eax
12924       3d/compare-eax-and 0/imm32/false
12925       b8/copy-to-eax 1/imm32/true
12926       75/jump-if-!= $same-register-spilled-before?:end/disp8
12927 $same-register-spilled-before?:continue:
12928       # curr -= 8
12929       81 5/subop/subtract %esi 8/imm32
12930       e9/jump loop/disp32
12931     }
12932 $same-register-spilled-before?:false:
12933     b8/copy-to-eax 0/imm32/false
12934 $same-register-spilled-before?:end:
12935     # . restore registers
12936     5f/pop-to-edi
12937     5e/pop-to-esi
12938     5b/pop-to-ebx
12939     5a/pop-to-edx
12940     59/pop-to-ecx
12941     # . epilogue
12942     89/<- %esp 5/r32/ebp
12943     5d/pop-to-ebp
12944     c3/return
12945 
12946 # Clean up global state for 'vars' until some block depth (inclusive).
12947 #
12948 # This would be a simple series of pops, if it wasn't for fn outputs, which
12949 # can occur anywhere in the stack.
12950 # So we have to _compact_ the entire array underlying the stack.
12951 #
12952 # We want to allow a fn output register to be written to by locals before the
12953 # output is set.
12954 # So fn outputs can't just be pushed at the start of the function.
12955 #
12956 # We want to allow other locals to shadow a fn output register after the
12957 # output is set.
12958 # So the output can't just always override anything in the stack. Sequence matters.
12959 clean-up-blocks:  # vars: (addr stack live-var), until-block-depth: int, fn: (addr function)
12960     # pseudocode:
12961     #   to = vars->top  (which points outside the stack)
12962     #   while true
12963     #     if to <= 0
12964     #       break
12965     #     var v = vars->data[to-1]
12966     #     if v.depth < until and !in-function-outputs?(fn, v)
12967     #       break
12968     #     --to
12969     #   from = to
12970     #   while true
12971     #     if from >= vars->top
12972     #       break
12973     #     assert(from >= to)
12974     #     v = vars->data[from]
12975     #     if in-function-outputs?(fn, v)
12976     #       if from > to
12977     #         vars->data[to] = vars->data[from]
12978     #       ++to
12979     #     ++from
12980     #   vars->top = to
12981     #
12982     # . prologue
12983     55/push-ebp
12984     89/<- %ebp 4/r32/esp
12985     # . save registers
12986     50/push-eax
12987     52/push-edx
12988     53/push-ebx
12989     56/push-esi
12990     57/push-edi
12991     # ebx = vars
12992     8b/-> *(ebp+8) 3/r32/ebx
12993     # edx = until-block-depth
12994     8b/-> *(ebp+0xc) 2/r32/edx
12995 $clean-up-blocks:phase1:
12996     # var to/edi: int = vars->top
12997     8b/-> *ebx 7/r32/edi
12998     {
12999 $clean-up-blocks:loop1:
13000       # if (to <= 0) break
13001       81 7/subop/compare %edi 0/imm32
13002       7e/jump-if-<= break/disp8
13003       # var v/eax: (addr var) = lookup(vars->data[to-1]->var)
13004       8d/copy-address *(ebx+edi-4) 0/r32/eax  # vars + 8 + to - 12
13005       (lookup *eax *(eax+4))  # => eax
13006       # if (v->block-depth >= until-block-depth) continue
13007       39/compare *(eax+0x10) 2/r32/edx  # Var-block-depth
13008       {
13009         7d/jump-if->= break/disp8
13010         # if (!in-function-outputs?(fn, v)) break
13011         (in-function-outputs? *(ebp+0x10) %eax)  # => eax
13012         3d/compare-eax-and 0/imm32/false
13013         74/jump-if-= $clean-up-blocks:phase2/disp8
13014       }
13015 $clean-up-blocks:loop1-continue:
13016       # --to
13017       81 5/subop/subtract %edi 0xc/imm32
13018       #
13019       eb/jump loop/disp8
13020     }
13021 $clean-up-blocks:phase2:
13022     # var from/esi: int = to
13023     89/<- %esi 7/r32/edi
13024     {
13025 $clean-up-blocks:loop2:
13026       # if (from >= vars->top) break
13027       3b/compare 6/r32/esi *ebx
13028       7d/jump-if->= break/disp8
13029       # var v/eax: (addr var) = lookup(vars->data[from]->var)
13030       8d/copy-address *(ebx+esi+8) 0/r32/eax
13031       (lookup *eax *(eax+4))  # => eax
13032       # if !in-function-outputs?(fn, v) continue
13033       (in-function-outputs? *(ebp+0x10) %eax)  # => eax
13034       3d/compare-eax-and 0/imm32/false
13035       74/jump-if-= $clean-up-blocks:loop2-continue/disp8
13036       # invariant: from >= to
13037       # if (from > to) vars->data[to] = vars->data[from]
13038       {
13039         39/compare %esi 7/r32/edi
13040         7e/jump-if-<= break/disp8
13041         56/push-esi
13042         57/push-edi
13043         # . var from/esi: (addr byte) = &vars->data[from]
13044         8d/copy-address *(ebx+esi+8) 6/r32/esi
13045         # . var to/edi: (addr byte) = &vars->data[to]
13046         8d/copy-address *(ebx+edi+8) 7/r32/edi
13047         # .
13048         8b/-> *esi 0/r32/eax
13049         89/<- *edi 0/r32/eax
13050         8b/-> *(esi+4) 0/r32/eax
13051         89/<- *(edi+4) 0/r32/eax
13052         8b/-> *(esi+8) 0/r32/eax
13053         89/<- *(edi+8) 0/r32/eax
13054         5f/pop-to-edi
13055         5e/pop-to-esi
13056       }
13057       # ++to
13058       81 0/subop/add %edi 0xc/imm32
13059 $clean-up-blocks:loop2-continue:
13060       # ++from
13061       81 0/subop/add %esi 0xc/imm32
13062       #
13063       eb/jump loop/disp8
13064     }
13065     89/<- *ebx 7/r32/edi
13066 $clean-up-blocks:end:
13067     # . restore registers
13068     5f/pop-to-edi
13069     5e/pop-to-esi
13070     5b/pop-to-ebx
13071     5a/pop-to-edx
13072     58/pop-to-eax
13073     # . epilogue
13074     89/<- %esp 5/r32/ebp
13075     5d/pop-to-ebp
13076     c3/return
13077 
13078 in-function-outputs?:  # fn: (addr function), target: (addr var) -> result/eax: boolean
13079     # . prologue
13080     55/push-ebp
13081     89/<- %ebp 4/r32/esp
13082     # . save registers
13083     51/push-ecx
13084     # var curr/ecx: (addr list var) = lookup(fn->outputs)
13085     8b/-> *(ebp+8) 1/r32/ecx
13086     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
13087     89/<- %ecx 0/r32/eax
13088     # while curr != null
13089     {
13090       81 7/subop/compare %ecx 0/imm32
13091       74/jump-if-= break/disp8
13092       # var v/eax: (addr var) = lookup(curr->value)
13093       (lookup *ecx *(ecx+4))  # List-value List-value => eax
13094       # if (v == target) return true
13095       39/compare *(ebp+0xc) 0/r32/eax
13096       b8/copy-to-eax 1/imm32/true
13097       74/jump-if-= $in-function-outputs?:end/disp8
13098       # curr = curr->next
13099       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
13100       89/<- %ecx 0/r32/eax
13101       #
13102       eb/jump loop/disp8
13103     }
13104     b8/copy-to-eax 0/imm32
13105 $in-function-outputs?: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 emit-subx-var-def:  # out: (addr buffered-file), stmt: (addr stmt)
13114     # . prologue
13115     55/push-ebp
13116     89/<- %ebp 4/r32/esp
13117     # . save registers
13118     50/push-eax
13119     51/push-ecx
13120     52/push-edx
13121     # eax = stmt
13122     8b/-> *(ebp+0xc) 0/r32/eax
13123     # var v/ecx: (addr var)
13124     (lookup *(eax+4) *(eax+8))  # Vardef-var Vardef-var => eax
13125     89/<- %ecx 0/r32/eax
13126     # v->block-depth = *Curr-block-depth
13127     8b/-> *Curr-block-depth 0/r32/eax
13128     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
13129     # var n/edx: int = size-of(stmt->var)
13130     (size-of %ecx)  # => eax
13131     89/<- %edx 0/r32/eax
13132     # *Curr-local-stack-offset -= n
13133     29/subtract-from *Curr-local-stack-offset 2/r32/edx
13134     # v->offset = *Curr-local-stack-offset
13135     8b/-> *Curr-local-stack-offset 0/r32/eax
13136     89/<- *(ecx+0x14) 0/r32/eax  # Var-offset
13137     # if v is an array, do something special
13138     {
13139       (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
13140       (is-mu-array? %eax)  # => eax
13141       3d/compare-eax-and 0/imm32/false
13142       0f 84/jump-if-= break/disp32
13143       # var array-size-without-size/edx: int = n-4
13144       81 5/subop/subtract %edx 4/imm32
13145       (emit-indent *(ebp+8) *Curr-block-depth)
13146       (write-buffered *(ebp+8) "(push-n-zero-bytes ")
13147       (write-int32-hex-buffered *(ebp+8) %edx)
13148       (write-buffered *(ebp+8) ")\n")
13149       (emit-indent *(ebp+8) *Curr-block-depth)
13150       (write-buffered *(ebp+8) "68/push ")
13151       (write-int32-hex-buffered *(ebp+8) %edx)
13152       (write-buffered *(ebp+8) "/imm32\n")
13153       eb/jump $emit-subx-var-def:end/disp8
13154     }
13155     # while n > 0
13156     {
13157       81 7/subop/compare %edx 0/imm32
13158       7e/jump-if-<= break/disp8
13159       (emit-indent *(ebp+8) *Curr-block-depth)
13160       (write-buffered *(ebp+8) "68/push 0/imm32\n")
13161       # n -= 4
13162       81 5/subop/subtract %edx 4/imm32
13163       #
13164       eb/jump loop/disp8
13165     }
13166 $emit-subx-var-def:end:
13167     # . restore registers
13168     5a/pop-to-edx
13169     59/pop-to-ecx
13170     58/pop-to-eax
13171     # . epilogue
13172     89/<- %esp 5/r32/ebp
13173     5d/pop-to-ebp
13174     c3/return
13175 
13176 emit-subx-stmt:  # out: (addr buffered-file), stmt: (addr stmt), primitives: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
13177     # . prologue
13178     55/push-ebp
13179     89/<- %ebp 4/r32/esp
13180     # . save registers
13181     50/push-eax
13182     51/push-ecx
13183     # - some special-case primitives that don't actually use the 'primitives' data structure
13184     # var op/ecx: (addr array byte) = lookup(stmt->operation)
13185     8b/-> *(ebp+0xc) 1/r32/ecx
13186     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
13187     89/<- %ecx 0/r32/eax
13188     # array size
13189     {
13190       # if (!string-equal?(stmt->operation, "length")) break
13191       (string-equal? %ecx "length")  # => eax
13192       3d/compare-eax-and 0/imm32
13193       0f 84/jump-if-= break/disp32
13194       (translate-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
13195       e9/jump $emit-subx-stmt:end/disp32
13196     }
13197     # index into array
13198     {
13199       # if (!string-equal?(stmt->operation, "index")) break
13200       (string-equal? %ecx "index")  # => eax
13201       3d/compare-eax-and 0/imm32
13202       0f 84/jump-if-= break/disp32
13203       (translate-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
13204       e9/jump $emit-subx-stmt:end/disp32
13205     }
13206     # compute-offset for index into array
13207     {
13208       # if (!string-equal?(stmt->operation, "compute-offset")) break
13209       (string-equal? %ecx "compute-offset")  # => eax
13210       3d/compare-eax-and 0/imm32
13211       0f 84/jump-if-= break/disp32
13212       (translate-mu-compute-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
13213       e9/jump $emit-subx-stmt:end/disp32
13214     }
13215     # get field from record
13216     {
13217       # if (!string-equal?(stmt->operation, "get")) break
13218       (string-equal? %ecx "get")  # => eax
13219       3d/compare-eax-and 0/imm32
13220       0f 84/jump-if-= break/disp32
13221       (translate-mu-get-stmt *(ebp+8) *(ebp+0xc))
13222       e9/jump $emit-subx-stmt:end/disp32
13223     }
13224     # - if stmt matches a primitive, emit it
13225     {
13226 $emit-subx-stmt:check-for-primitive:
13227       # var curr/eax: (addr primitive)
13228       (find-matching-primitive *(ebp+0x10) *(ebp+0xc))  # primitives, stmt => eax
13229       3d/compare-eax-and 0/imm32
13230       74/jump-if-= break/disp8
13231 $emit-subx-stmt:primitive:
13232       (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax)  # out, stmt, curr
13233       e9/jump $emit-subx-stmt:end/disp32
13234     }
13235     # - otherwise emit a call
13236     # TODO: type-checking
13237 $emit-subx-stmt:call:
13238     (emit-call *(ebp+8) *(ebp+0xc))
13239 $emit-subx-stmt:end:
13240     # . restore registers
13241     59/pop-to-ecx
13242     58/pop-to-eax
13243     # . epilogue
13244     89/<- %esp 5/r32/ebp
13245     5d/pop-to-ebp
13246     c3/return
13247 
13248 translate-mu-length-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
13249     # . prologue
13250     55/push-ebp
13251     89/<- %ebp 4/r32/esp
13252     # . save registers
13253     50/push-eax
13254     51/push-ecx
13255     52/push-edx
13256     53/push-ebx
13257     56/push-esi
13258     # esi = stmt
13259     8b/-> *(ebp+0xc) 6/r32/esi
13260     # var base/ebx: (addr var) = stmt->inouts[0]->value
13261     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13262     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13263     89/<- %ebx 0/r32/eax
13264     # var elemsize/ecx: int = array-element-size(base)
13265     (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
13266     89/<- %ecx 0/r32/eax
13267     # var outreg/edx: (addr array byte) = stmt->outputs[0]->value->register
13268     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13269     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13270     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
13271     89/<- %edx 0/r32/eax
13272     # if elemsize == 1
13273     {
13274       81 7/subop/compare %ecx 1/imm32
13275       75/jump-if-!= break/disp8
13276 $translate-mu-length-stmt:size-1:
13277       (emit-save-size-to *(ebp+8) %ebx %edx)
13278       e9/jump $translate-mu-length-stmt:end/disp32
13279     }
13280     # if elemsize is a power of 2 less than 256
13281     {
13282       (power-of-2? %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
13283       3d/compare-eax-and 0/imm32/false
13284       74/jump-if-= break/disp8
13285       81 7/subop/compare %ecx 0xff/imm32
13286       7f/jump-if-> break/disp8
13287 $translate-mu-length-stmt:size-power-of-2:
13288       (emit-save-size-to *(ebp+8) %ebx %edx)
13289       (emit-divide-by-shift-right *(ebp+8) %edx %ecx)
13290       e9/jump $translate-mu-length-stmt:end/disp32
13291     }
13292     # otherwise, the complex case
13293     # . emit register spills
13294     {
13295 $translate-mu-length-stmt:complex:
13296       (string-equal? %edx "eax")  # => eax
13297       3d/compare-eax-and 0/imm32/false
13298       75/break-if-!= break/disp8
13299       (emit-indent *(ebp+8) *Curr-block-depth)
13300       (write-buffered *(ebp+8) "50/push-eax\n")
13301     }
13302     {
13303       (string-equal? %edx "ecx")  # => eax
13304       3d/compare-eax-and 0/imm32/false
13305       75/break-if-!= break/disp8
13306       (emit-indent *(ebp+8) *Curr-block-depth)
13307       (write-buffered *(ebp+8) "51/push-ecx\n")
13308     }
13309     {
13310       (string-equal? %edx "edx")  # => eax
13311       3d/compare-eax-and 0/imm32/false
13312       75/break-if-!= break/disp8
13313       (emit-indent *(ebp+8) *Curr-block-depth)
13314       (write-buffered *(ebp+8) "52/push-edx\n")
13315     }
13316     # .
13317     (emit-save-size-to *(ebp+8) %ebx "eax")
13318     (emit-indent *(ebp+8) *Curr-block-depth)
13319     (write-buffered *(ebp+8) "31/xor %edx 2/r32/edx\n")
13320     (emit-indent *(ebp+8) *Curr-block-depth)
13321     (write-buffered *(ebp+8) "b9/copy-to-ecx ")
13322     (write-int32-hex-buffered *(ebp+8) %ecx)
13323     (write-buffered *(ebp+8) "/imm32\n")
13324     (emit-indent *(ebp+8) *Curr-block-depth)
13325     (write-buffered *(ebp+8) "f7 7/subop/idiv-eax-edx-by %ecx\n")
13326     {
13327       (string-equal? %edx "eax")  # => eax
13328       3d/compare-eax-and 0/imm32/false
13329       75/break-if-!= break/disp8
13330       (emit-indent *(ebp+8) *Curr-block-depth)
13331       (write-buffered *(ebp+8) "89/<- %")
13332       (write-buffered *(ebp+8) %edx)
13333       (write-buffered *(ebp+8) " 0/r32/eax\n")
13334     }
13335     # . emit register restores
13336     {
13337       (string-equal? %edx "edx")  # => eax
13338       3d/compare-eax-and 0/imm32/false
13339       75/break-if-!= break/disp8
13340       (emit-indent *(ebp+8) *Curr-block-depth)
13341       (write-buffered *(ebp+8) "5a/pop-to-edx\n")
13342     }
13343     {
13344       (string-equal? %edx "ecx")  # => eax
13345       3d/compare-eax-and 0/imm32/false
13346       75/break-if-!= break/disp8
13347       (emit-indent *(ebp+8) *Curr-block-depth)
13348       (write-buffered *(ebp+8) "59/pop-to-ecx\n")
13349     }
13350     {
13351       (string-equal? %edx "eax")  # => eax
13352       3d/compare-eax-and 0/imm32/false
13353       75/break-if-!= break/disp8
13354       (emit-indent *(ebp+8) *Curr-block-depth)
13355       (write-buffered *(ebp+8) "58/pop-to-eax\n")
13356     }
13357 $translate-mu-length-stmt:end:
13358     # . restore registers
13359     5e/pop-to-esi
13360     5b/pop-to-ebx
13361     5a/pop-to-edx
13362     59/pop-to-ecx
13363     58/pop-to-eax
13364     # . epilogue
13365     89/<- %esp 5/r32/ebp
13366     5d/pop-to-ebp
13367     c3/return
13368 
13369 array-element-size:  # arr: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
13370     # . prologue
13371     55/push-ebp
13372     89/<- %ebp 4/r32/esp
13373     #
13374     (array-element-type-id *(ebp+8) *(ebp+0xc) *(ebp+0x10))  # => eax
13375     (size-of-type-id-as-array-element %eax)  # => eax
13376 $array-element-size:end:
13377     # . epilogue
13378     89/<- %esp 5/r32/ebp
13379     5d/pop-to-ebp
13380     c3/return
13381 
13382 size-of-type-id-as-array-element:  # t: type-id -> result/eax: int
13383     # . prologue
13384     55/push-ebp
13385     89/<- %ebp 4/r32/esp
13386     # eax = t
13387     8b/-> *(ebp+8) 0/r32/eax
13388     # if t is 'byte', size is 1
13389     3d/compare-eax-and 8/imm32/byte
13390     {
13391       75/jump-if-!= break/disp8
13392       b8/copy-to-eax 1/imm32
13393       eb/jump $array-element-size:end/disp8
13394     }
13395     # otherwise proceed as usual
13396     (size-of-type-id %eax)  # => eax
13397 $size-of-type-id-as-array-element:end:
13398     # . epilogue
13399     89/<- %esp 5/r32/ebp
13400     5d/pop-to-ebp
13401     c3/return
13402 
13403 emit-save-size-to:  # out: (addr buffered-file), base: (addr var), outreg: (addr array byte)
13404     # . prologue
13405     55/push-ebp
13406     89/<- %ebp 4/r32/esp
13407     # . save registers
13408     50/push-eax
13409     53/push-ebx
13410     # ebx = base
13411     8b/-> *(ebp+0xc) 3/r32/ebx
13412     (emit-indent *(ebp+8) *Curr-block-depth)
13413     (write-buffered *(ebp+8) "8b/-> *")
13414     # if base is an (addr array ...) in a register
13415     {
13416       81 7/subop/compare *(ebx+0x18)) 0/imm32  # Var-register
13417       74/jump-if-= break/disp8
13418 $emit-save-size-to:emit-base-from-register:
13419       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
13420       (write-buffered *(ebp+8) %eax)
13421       eb/jump $emit-save-size-to:emit-output/disp8
13422     }
13423     # otherwise if base is an (array ...) on the stack
13424     {
13425       81 7/subop/compare *(ebx+0x14)) 0/imm32  # Var-offset
13426       74/jump-if-= break/disp8
13427 $emit-save-size-to:emit-base-from-stack:
13428       (write-buffered *(ebp+8) "(ebp+")
13429       (write-int32-hex-buffered *(ebp+8) *(ebx+0x14))  # Var-offset
13430       (write-buffered *(ebp+8) ")")
13431     }
13432 $emit-save-size-to:emit-output:
13433     (write-buffered *(ebp+8) " ")
13434     (get Mu-registers *(ebp+0x10) 0xc "Mu-registers")  # => eax
13435     (write-int32-hex-buffered *(ebp+8) *eax)
13436     (write-buffered *(ebp+8) "/r32\n")
13437 $emit-save-size-to:end:
13438     # . restore registers
13439     5b/pop-to-ebx
13440     58/pop-to-eax
13441     # . epilogue
13442     89/<- %esp 5/r32/ebp
13443     5d/pop-to-ebp
13444     c3/return
13445 
13446 emit-divide-by-shift-right:  # out: (addr buffered-file), reg: (addr array byte), size: int
13447     # . prologue
13448     55/push-ebp
13449     89/<- %ebp 4/r32/esp
13450     # . save registers
13451     50/push-eax
13452     #
13453     (emit-indent *(ebp+8) *Curr-block-depth)
13454     (write-buffered *(ebp+8) "c1/shift 5/subop/>> %")
13455     (write-buffered *(ebp+8) *(ebp+0xc))
13456     (write-buffered *(ebp+8) Space)
13457     (num-shift-rights *(ebp+0x10))  # => eax
13458     (write-int32-hex-buffered *(ebp+8) %eax)
13459     (write-buffered *(ebp+8) "/imm8\n")
13460 $emit-divide-by-shift-right:end:
13461     # . restore registers
13462     58/pop-to-eax
13463     # . epilogue
13464     89/<- %esp 5/r32/ebp
13465     5d/pop-to-ebp
13466     c3/return
13467 
13468 translate-mu-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
13469     # . prologue
13470     55/push-ebp
13471     89/<- %ebp 4/r32/esp
13472     # . save registers
13473     51/push-ecx
13474     # ecx = stmt
13475     8b/-> *(ebp+0xc) 1/r32/ecx
13476     # var base/ecx: (addr var) = stmt->inouts[0]
13477     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13478     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13479     89/<- %ecx 0/r32/eax
13480     # if (var->register) do one thing
13481     {
13482       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
13483       74/jump-if-= break/disp8
13484       # TODO: ensure there's no dereference
13485       (translate-mu-index-stmt-with-array-in-register *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13486       eb/jump $translate-mu-index-stmt:end/disp8
13487     }
13488     # if (var->offset) do a different thing
13489     {
13490       81 7/subop/compare *(ecx+0x14) 0/imm32  # Var-offset
13491       74/jump-if-= break/disp8
13492       # TODO: ensure there's no dereference
13493       (translate-mu-index-stmt-with-array-on-stack *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13494       eb/jump $translate-mu-index-stmt:end/disp8
13495     }
13496 $translate-mu-index-stmt:end:
13497     # . restore registers
13498     59/pop-to-ecx
13499     # . epilogue
13500     89/<- %esp 5/r32/ebp
13501     5d/pop-to-ebp
13502     c3/return
13503 
13504 $translate-mu-index-stmt-with-array:error1:
13505     (write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input must either lie in a register or be a literal\n")
13506     (flush *(ebp+0x10))
13507     (stop *(ebp+0x14) 1)
13508     # never gets here
13509 
13510 $translate-mu-index-stmt-with-array:error2:
13511     (write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input when in a register must be an int or offset\n")
13512     (flush *(ebp+0x10))
13513     (stop *(ebp+0x14) 1)
13514     # never gets here
13515 
13516 translate-mu-index-stmt-with-array-in-register:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
13517     # . prologue
13518     55/push-ebp
13519     89/<- %ebp 4/r32/esp
13520     # . save registers
13521     50/push-eax
13522     51/push-ecx
13523     52/push-edx
13524     53/push-ebx
13525     #
13526     (emit-indent *(ebp+8) *Curr-block-depth)
13527     (write-buffered *(ebp+8) "8d/copy-address *(")
13528     # TODO: ensure inouts[0] is in a register and not dereferenced
13529 $translate-mu-index-stmt-with-array-in-register:emit-base:
13530     # ecx = stmt
13531     8b/-> *(ebp+0xc) 1/r32/ecx
13532     # var base/ebx: (addr var) = inouts[0]
13533     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13534     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13535     89/<- %ebx 0/r32/eax
13536     # print base->register " + "
13537     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
13538     (write-buffered *(ebp+8) %eax)
13539     (write-buffered *(ebp+8) " + ")
13540     # var index/edx: (addr var) = inouts[1]
13541     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13542     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13543     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13544     89/<- %edx 0/r32/eax
13545     # if index->register
13546     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
13547     {
13548       0f 84/jump-if-= break/disp32
13549 $translate-mu-index-stmt-with-array-in-register:emit-register-index:
13550       # if index is an int
13551       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
13552       (is-simple-mu-type? %eax 1)  # int => eax
13553       3d/compare-eax-and 0/imm32/false
13554       {
13555         0f 84/jump-if-= break/disp32
13556 $translate-mu-index-stmt-with-array-in-register:emit-int-register-index:
13557         # print index->register "<<" log2(array-element-size(base)) " + 4) "
13558         # . index->register "<<"
13559         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
13560         (write-buffered *(ebp+8) %eax)
13561         (write-buffered *(ebp+8) "<<")
13562         # . log2(array-element-size(base->type))
13563         # TODO: ensure size is a power of 2
13564         (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
13565         (num-shift-rights %eax)  # => eax
13566         (write-int32-hex-buffered *(ebp+8) %eax)
13567         e9/jump $translate-mu-index-stmt-with-array-in-register:emit-register-index-done/disp32
13568       }
13569       # if index->type is any other atom, abort
13570       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
13571       81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
13572       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
13573       # if index has type (offset ...)
13574       (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
13575       (is-simple-mu-type? %eax 7)  # => eax
13576       3d/compare-eax-and 0/imm32/false
13577       {
13578         0f 84/jump-if-= break/disp32
13579         # print index->register
13580 $translate-mu-index-stmt-with-array-in-register:emit-offset-register-index:
13581         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
13582         (write-buffered *(ebp+8) %eax)
13583       }
13584 $translate-mu-index-stmt-with-array-in-register:emit-register-index-done:
13585       (write-buffered *(ebp+8) " + 4) ")
13586       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
13587     }
13588     # otherwise if index is a literal
13589     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
13590     (is-simple-mu-type? %eax 0)  # => eax
13591     3d/compare-eax-and 0/imm32/false
13592     {
13593       0f 84/jump-if-= break/disp32
13594 $translate-mu-index-stmt-with-array-in-register:emit-literal-index:
13595       # var index-value/edx: int = parse-hex-int(index->name)
13596       (lookup *edx *(edx+4))  # Var-name Var-name => eax
13597       (parse-hex-int %eax)  # => eax
13598       89/<- %edx 0/r32/eax
13599       # offset = idx-value * array-element-size(base->type)
13600       (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
13601       f7 4/subop/multiply-into-eax %edx  # clobbers edx
13602       # offset += 4 for array size
13603       05/add-to-eax 4/imm32
13604       # TODO: check edx for overflow
13605       # print offset
13606       (write-int32-hex-buffered *(ebp+8) %eax)
13607       (write-buffered *(ebp+8) ") ")
13608       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
13609     }
13610     # otherwise abort
13611     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
13612 $translate-mu-index-stmt-with-array-in-register:emit-output:
13613     # outputs[0] "/r32"
13614     8b/-> *(ebp+0xc) 1/r32/ecx
13615     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13616     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13617     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
13618     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
13619     (write-int32-hex-buffered *(ebp+8) *eax)
13620     (write-buffered *(ebp+8) "/r32\n")
13621 $translate-mu-index-stmt-with-array-in-register:end:
13622     # . restore registers
13623     5b/pop-to-ebx
13624     5a/pop-to-edx
13625     59/pop-to-ecx
13626     58/pop-to-eax
13627     # . epilogue
13628     89/<- %esp 5/r32/ebp
13629     5d/pop-to-ebp
13630     c3/return
13631 
13632 translate-mu-index-stmt-with-array-on-stack:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
13633     # . prologue
13634     55/push-ebp
13635     89/<- %ebp 4/r32/esp
13636     # . save registers
13637     50/push-eax
13638     51/push-ecx
13639     52/push-edx
13640     53/push-ebx
13641     #
13642     (emit-indent *(ebp+8) *Curr-block-depth)
13643     (write-buffered *(ebp+8) "8d/copy-address *(ebp + ")
13644     # var curr/edx: (addr stmt-var) = lookup(stmt->inouts)
13645     8b/-> *(ebp+0xc) 0/r32/eax
13646     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13647     89/<- %edx 0/r32/eax
13648     # var base/ecx: (addr var) = lookup(curr->value)
13649     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13650     89/<- %ecx 0/r32/eax
13651     # var curr2/eax: (addr stmt-var) = lookup(curr->next)
13652     (lookup *(edx+8) *(edx+0xc))  # Stmt-var-next Stmt-var-next => eax
13653     # var index/edx: (handle var) = curr2->value
13654     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13655     89/<- %edx 0/r32/eax
13656     # if index->register
13657     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
13658     {
13659       0f 84/jump-if-= break/disp32
13660 $translate-mu-index-stmt-with-array-on-stack:emit-register-index:
13661       # if index is an int
13662       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
13663       (is-simple-mu-type? %eax 1)  # int => eax
13664       3d/compare-eax-and 0/imm32/false
13665       {
13666         0f 84/jump-if-= break/disp32
13667 $translate-mu-index-stmt-with-array-on-stack:emit-int-register-index:
13668         # print index->register "<<" log2(array-element-size(base)) " + " base->offset+4
13669         # . inouts[1]->register "<<"
13670         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
13671         (write-buffered *(ebp+8) %eax)
13672         (write-buffered *(ebp+8) "<<")
13673         # . log2(array-element-size(base))
13674         # TODO: ensure size is a power of 2
13675         (array-element-size %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
13676         (num-shift-rights %eax)  # => eax
13677         (write-int32-hex-buffered *(ebp+8) %eax)
13678         #
13679         (write-buffered *(ebp+8) " + ")
13680         #
13681         8b/-> *(ecx+0x14) 0/r32/eax  # Var-offset
13682         05/add-to-eax 4/imm32  # for array length
13683         (write-int32-hex-buffered *(ebp+8) %eax)
13684         e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done/disp32
13685       }
13686       # if index->type is any other atom, abort
13687       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
13688       81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
13689       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
13690       # if index has type (offset ...)
13691       (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
13692       (is-simple-mu-type? %eax 7)  # => eax
13693       3d/compare-eax-and 0/imm32/false
13694       {
13695         0f 84/jump-if-= break/disp32
13696         # print index->register
13697 $translate-mu-index-stmt-with-array-on-stack:emit-offset-register-index:
13698         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
13699         (write-buffered *(ebp+8) %eax)
13700       }
13701 $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done:
13702       (write-buffered *(ebp+8) ") ")
13703       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
13704     }
13705     # otherwise if index is a literal
13706     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
13707     (is-simple-mu-type? %eax 0)  # => eax
13708     3d/compare-eax-and 0/imm32/false
13709     {
13710       0f 84/jump-if-= break/disp32
13711 $translate-mu-index-stmt-with-array-on-stack:emit-literal-index:
13712       # var idx-value/edx: int = parse-hex-int(index->name)
13713       (lookup *edx *(edx+4))  # Var-name Var-name => eax
13714       (parse-hex-int %eax)  # Var-name => eax
13715       89/<- %edx 0/r32/eax
13716       # offset = idx-value * array-element-size(base)
13717       (array-element-size %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
13718       f7 4/subop/multiply-into-eax %edx  # clobbers edx
13719       # offset += base->offset
13720       03/add *(ecx+0x14) 0/r32/eax  # Var-offset
13721       # offset += 4 for array size
13722       05/add-to-eax 4/imm32
13723       # TODO: check edx for overflow
13724       # print offset
13725       (write-int32-hex-buffered *(ebp+8) %eax)
13726       (write-buffered *(ebp+8) ") ")
13727       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
13728     }
13729     # otherwise abort
13730     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
13731 $translate-mu-index-stmt-with-array-on-stack:emit-output:
13732     # outputs[0] "/r32"
13733     8b/-> *(ebp+0xc) 0/r32/eax
13734     (lookup *(eax+0x14) *(eax+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13735     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13736     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
13737     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
13738     (write-int32-hex-buffered *(ebp+8) *eax)
13739     (write-buffered *(ebp+8) "/r32\n")
13740 $translate-mu-index-stmt-with-array-on-stack:end:
13741     # . restore registers
13742     5b/pop-to-ebx
13743     5a/pop-to-edx
13744     59/pop-to-ecx
13745     58/pop-to-eax
13746     # . epilogue
13747     89/<- %esp 5/r32/ebp
13748     5d/pop-to-ebp
13749     c3/return
13750 
13751 translate-mu-compute-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
13752     # . prologue
13753     55/push-ebp
13754     89/<- %ebp 4/r32/esp
13755     # . save registers
13756     50/push-eax
13757     51/push-ecx
13758     52/push-edx
13759     53/push-ebx
13760     #
13761     (emit-indent *(ebp+8) *Curr-block-depth)
13762     (write-buffered *(ebp+8) "69/multiply")
13763     # ecx = stmt
13764     8b/-> *(ebp+0xc) 1/r32/ecx
13765     # var first-inout/ebx: (addr stmt-var) = stmt->inouts[0]
13766     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13767     89/<- %ebx 0/r32/eax
13768 $translate-mu-compute-index-stmt:emit-index:
13769     (lookup *(ebx+8) *(ebx+0xc))  # Stmt-var-next Stmt-var-next => eax
13770     (emit-subx-var-as-rm32 *(ebp+8) %eax)
13771     (write-buffered *(ebp+8) Space)
13772 $translate-mu-compute-index-stmt:emit-elem-size:
13773     # var base/ebx: (addr var)
13774     (lookup *ebx *(ebx+4))  # Stmt-var-value Stmt-var-value => eax
13775     89/<- %ebx 0/r32/eax
13776     # print array-element-size(base)
13777     (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
13778     (write-int32-hex-buffered *(ebp+8) %eax)
13779     (write-buffered *(ebp+8) "/imm32 ")
13780 $translate-mu-compute-index-stmt:emit-output:
13781     # outputs[0] "/r32"
13782     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13783     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13784     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
13785     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
13786     (write-int32-hex-buffered *(ebp+8) *eax)
13787     (write-buffered *(ebp+8) "/r32\n")
13788 $translate-mu-compute-index-stmt:end:
13789     # . restore registers
13790     5b/pop-to-ebx
13791     5a/pop-to-edx
13792     59/pop-to-ecx
13793     58/pop-to-eax
13794     # . epilogue
13795     89/<- %esp 5/r32/ebp
13796     5d/pop-to-ebp
13797     c3/return
13798 
13799 translate-mu-get-stmt:  # out: (addr buffered-file), stmt: (addr stmt)
13800     # . prologue
13801     55/push-ebp
13802     89/<- %ebp 4/r32/esp
13803     # . save registers
13804     50/push-eax
13805     51/push-ecx
13806     52/push-edx
13807     #
13808     (emit-indent *(ebp+8) *Curr-block-depth)
13809     (write-buffered *(ebp+8) "8d/copy-address ")
13810     # ecx = stmt
13811     8b/-> *(ebp+0xc) 1/r32/ecx
13812     # var offset/edx: int = get offset of stmt
13813     (mu-get-offset %ecx)  # => eax
13814     89/<- %edx 0/r32/eax
13815     # var base/eax: (addr var) = stmt->inouts->value
13816     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13817     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13818     # if base is in a register
13819     81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
13820     {
13821       0f 84/jump-if-= break/disp32
13822 $translate-mu-get-stmt:emit-register-input:
13823       # emit "*(" base->register " + " offset ") "
13824       (write-buffered *(ebp+8) "*(")
13825       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
13826       (write-buffered *(ebp+8) %eax)
13827       (write-buffered *(ebp+8) " + ")
13828       (write-int32-hex-buffered *(ebp+8) %edx)
13829       (write-buffered *(ebp+8) ") ")
13830       e9/jump $translate-mu-get-stmt:emit-output/disp32
13831     }
13832     # otherwise base is on the stack
13833     {
13834 $translate-mu-get-stmt:emit-stack-input:
13835       # emit "*(ebp + " inouts[0]->stack-offset + offset ") "
13836       (write-buffered *(ebp+8) "*(ebp+")
13837       03/add *(eax+0x14) 2/r32/edx  # Var-offset
13838       (write-int32-hex-buffered *(ebp+8) %edx)
13839       (write-buffered *(ebp+8) ") ")
13840       eb/jump $translate-mu-get-stmt:emit-output/disp8
13841     }
13842 $translate-mu-get-stmt:emit-output:
13843     # var output/eax: (addr var) = stmt->outputs->value
13844     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13845     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13846     # emit offset->register "/r32"
13847     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
13848     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
13849     (write-int32-hex-buffered *(ebp+8) *eax)
13850     (write-buffered *(ebp+8) "/r32\n")
13851 $translate-mu-get-stmt:end:
13852     # . restore registers
13853     5a/pop-to-edx
13854     59/pop-to-ecx
13855     58/pop-to-eax
13856     # . epilogue
13857     89/<- %esp 5/r32/ebp
13858     5d/pop-to-ebp
13859     c3/return
13860 
13861 array-element-type-id:  # v: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: type-id
13862     # precondition: n is positive
13863     # . prologue
13864     55/push-ebp
13865     89/<- %ebp 4/r32/esp
13866     #
13867     8b/-> *(ebp+8) 0/r32/eax
13868     # var t/eax: (addr tree type-id)
13869     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
13870     # if t == 0 abort
13871     3d/compare-eax-with 0/imm32
13872     0f 84/jump-if-== $array-element-type-id:error0/disp32
13873     # if t->is-atom? abort
13874     81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
13875     0f 85/jump-if-!= $array-element-type-id:error1/disp32
13876     # if (t->left == addr) t = t->right
13877     {
13878       50/push-eax
13879       (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
13880       (is-simple-mu-type? %eax 2)  # addr => eax
13881       3d/compare-eax-with 0/imm32/false
13882       58/pop-to-eax
13883       74/jump-if-= break/disp8
13884 $array-element-type-id:skip-addr:
13885       (lookup *(eax+0xc) *(eax+0x10))  # Tree-right Tree-right => eax
13886     }
13887     # if t == 0 abort
13888     3d/compare-eax-with 0/imm32
13889     0f 84/jump-if-= $array-element-type-id:error2/disp32
13890     # if t->is-atom? abort
13891     81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
13892     0f 85/jump-if-!= $array-element-type-id:error2/disp32
13893     # if t->left != array abort
13894     {
13895       50/push-eax
13896       (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
13897       (is-simple-mu-type? %eax 3)  # array => eax
13898       3d/compare-eax-with 0/imm32/false
13899       58/pop-to-eax
13900 $array-element-type-id:no-array:
13901       0f 84/jump-if-= $array-element-type-id:error2/disp32
13902     }
13903 $array-element-type-id:skip-array:
13904     # t = t->right
13905     (lookup *(eax+0xc) *(eax+0x10))  # Tree-right Tree-right => eax
13906     # if t == 0 abort
13907     3d/compare-eax-with 0/imm32
13908     0f 84/jump-if-= $array-element-type-id:error2/disp32
13909     # if t->is-atom? abort
13910     81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
13911     0f 85/jump-if-!= $array-element-type-id:error2/disp32
13912     # return t->left->value
13913     (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
13914     8b/-> *(eax+4) 0/r32/eax  # Tree-value
13915 $array-element-type-id:end:
13916     # . epilogue
13917     89/<- %esp 5/r32/ebp
13918     5d/pop-to-ebp
13919     c3/return
13920 
13921 $array-element-type-id:error0:
13922     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
13923     50/push-eax
13924     8b/-> *(ebp+8) 0/r32/eax
13925     (lookup *eax *(eax+4))  # Var-name Var-name => eax
13926     (write-buffered *(ebp+0xc) %eax)
13927     58/pop-to-eax
13928     (write-buffered *(ebp+0xc) "' has no type\n")
13929     (flush *(ebp+0xc))
13930     (stop *(ebp+0x10) 1)
13931     # never gets here
13932 
13933 $array-element-type-id:error1:
13934     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
13935     50/push-eax
13936     8b/-> *(ebp+8) 0/r32/eax
13937     (lookup *eax *(eax+4))  # Var-name Var-name => eax
13938     (write-buffered *(ebp+0xc) %eax)
13939     58/pop-to-eax
13940     (write-buffered *(ebp+0xc) "' has atomic type ")
13941     (write-int32-hex-buffered *(ebp+0xc) *(eax+4))  # Tree-value
13942     (write-buffered *(ebp+0xc) Newline)
13943     (flush *(ebp+0xc))
13944     (stop *(ebp+0x10) 1)
13945     # never gets here
13946 
13947 $array-element-type-id:error2:
13948     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
13949     50/push-eax
13950     8b/-> *(ebp+8) 0/r32/eax
13951     (lookup *eax *(eax+4))  # Var-name Var-name => eax
13952     (write-buffered *(ebp+0xc) %eax)
13953     58/pop-to-eax
13954     (write-buffered *(ebp+0xc) "' has non-array type\n")
13955     (flush *(ebp+0xc))
13956     (stop *(ebp+0x10) 1)
13957     # never gets here
13958 
13959 power-of-2?:  # n: int, err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: boolean
13960     # precondition: n is positive
13961     # . prologue
13962     55/push-ebp
13963     89/<- %ebp 4/r32/esp
13964     # eax = n
13965     8b/-> *(ebp+8) 0/r32/eax
13966     # if (n < 0) abort
13967     3d/compare-eax-with 0/imm32
13968     0f 8c/jump-if-< $power-of-2?:abort/disp32
13969     # var tmp/eax: int = n-1
13970     48/decrement-eax
13971     # var tmp2/eax: int = n & tmp
13972     23/and-> *(ebp+8) 0/r32/eax
13973     # return (tmp2 == 0)
13974     3d/compare-eax-and 0/imm32
13975     0f 94/set-byte-if-= %al
13976     81 4/subop/and %eax 0xff/imm32
13977 $power-of-2?:end:
13978     # . epilogue
13979     89/<- %esp 5/r32/ebp
13980     5d/pop-to-ebp
13981     c3/return
13982 
13983 $power-of-2?:abort:
13984     (write-buffered *(ebp+0xc) "power-of-2?: negative number\n")
13985     (flush *(ebp+0xc))
13986     (stop *(ebp+0x10) 1)
13987     # never gets here
13988 
13989 num-shift-rights:  # n: int -> result/eax: int
13990     # precondition: n is a positive power of 2
13991     # . prologue
13992     55/push-ebp
13993     89/<- %ebp 4/r32/esp
13994     # . save registers
13995     51/push-ecx
13996     # var curr/ecx: int = n
13997     8b/-> *(ebp+8) 1/r32/ecx
13998     # result = 0
13999     b8/copy-to-eax 0/imm32
14000     {
14001       # if (curr <= 1) break
14002       81 7/subop/compare %ecx 1/imm32
14003       7e/jump-if-<= break/disp8
14004       40/increment-eax
14005       c1/shift 5/subop/arithmetic-right %ecx 1/imm8
14006       eb/jump loop/disp8
14007     }
14008 $num-shift-rights:end:
14009     # . restore registers
14010     59/pop-to-ecx
14011     # . epilogue
14012     89/<- %esp 5/r32/ebp
14013     5d/pop-to-ebp
14014     c3/return
14015 
14016 mu-get-offset:  # stmt: (addr stmt) -> result/eax: int
14017     # . prologue
14018     55/push-ebp
14019     89/<- %ebp 4/r32/esp
14020     # var second-inout/eax: (addr stmt-var) = stmt->inouts->next
14021     8b/-> *(ebp+8) 0/r32/eax
14022     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
14023     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
14024     # var output-var/eax: (addr var) = second-inout->value
14025     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
14026 #?     (write-buffered Stderr "mu-get-offset: ")
14027 #?     (write-int32-hex-buffered Stderr %eax)
14028 #?     (write-buffered Stderr " name: ")
14029 #?     50/push-eax
14030 #?     (lookup *eax *(eax+4))  # Var-name
14031 #?     (write-buffered Stderr %eax)
14032 #?     58/pop-to-eax
14033 #?     (write-buffered Stderr Newline)
14034 #?     (flush Stderr)
14035     # return output-var->stack-offset
14036     8b/-> *(eax+0x14) 0/r32/eax  # Var-offset
14037 #?     (write-buffered Stderr "=> ")
14038 #?     (write-int32-hex-buffered Stderr %eax)
14039 #?     (write-buffered Stderr Newline)
14040 #?     (flush Stderr)
14041 $emit-get-offset:end:
14042     # . epilogue
14043     89/<- %esp 5/r32/ebp
14044     5d/pop-to-ebp
14045     c3/return
14046 
14047 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)
14048     # . prologue
14049     55/push-ebp
14050     89/<- %ebp 4/r32/esp
14051     # . save registers
14052     50/push-eax
14053     51/push-ecx
14054     56/push-esi
14055     # esi = block
14056     8b/-> *(ebp+0xc) 6/r32/esi
14057     # block->var->block-depth = *Curr-block-depth
14058     (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
14059     8b/-> *Curr-block-depth 1/r32/ecx
14060     89/<- *(eax+0x10) 1/r32/ecx  # Var-block-depth
14061     # var stmts/eax: (addr list stmt) = lookup(block->statements)
14062     (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
14063     #
14064     {
14065 $emit-subx-block:check-empty:
14066       3d/compare-eax-and 0/imm32
14067       0f 84/jump-if-= break/disp32
14068       (emit-indent *(ebp+8) *Curr-block-depth)
14069       (write-buffered *(ebp+8) "{\n")
14070       # var v/ecx: (addr var) = lookup(block->var)
14071       (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
14072       89/<- %ecx 0/r32/eax
14073       #
14074       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
14075       (write-buffered *(ebp+8) %eax)
14076       (write-buffered *(ebp+8) ":loop:\n")
14077       ff 0/subop/increment *Curr-block-depth
14078       (push *(ebp+0x10) *(esi+0xc))  # Block-var
14079       (push *(ebp+0x10) *(esi+0x10))  # Block-var
14080       (push *(ebp+0x10) 0)  # false
14081       # emit block->statements
14082       (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
14083       (emit-subx-stmt-list *(ebp+8) %eax *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
14084       (pop *(ebp+0x10))  # => eax
14085       (pop *(ebp+0x10))  # => eax
14086       (pop *(ebp+0x10))  # => eax
14087       ff 1/subop/decrement *Curr-block-depth
14088       (emit-indent *(ebp+8) *Curr-block-depth)
14089       (write-buffered *(ebp+8) "}\n")
14090       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
14091       (write-buffered *(ebp+8) %eax)
14092       (write-buffered *(ebp+8) ":break:\n")
14093     }
14094 $emit-subx-block:end:
14095     # . restore registers
14096     5e/pop-to-esi
14097     59/pop-to-ecx
14098     58/pop-to-eax
14099     # . epilogue
14100     89/<- %esp 5/r32/ebp
14101     5d/pop-to-ebp
14102     c3/return
14103 
14104 # Primitives supported
14105 # See mu_instructions for a summary of this linked-list data structure.
14106 #
14107 # For each operation, put variants with hard-coded registers before flexible ones.
14108 #
14109 # Unfortunately, our restrictions on addresses require that various fields in
14110 # primitives be handles, which complicates these definitions.
14111 #   - we need to insert dummy fields all over the place for fake alloc-ids
14112 #   - we can't use our syntax sugar of quoted literals for string fields
14113 #
14114 # Fake alloc-ids are needed because our type definitions up top require
14115 # handles but it's clearer to statically allocate these long-lived objects.
14116 # Fake alloc-ids are perfectly safe, but they can't be reclaimed.
14117 #
14118 # Every 'object' below starts with a fake alloc-id. It may also contain other
14119 # fake alloc-ids for various handle fields.
14120 #
14121 # I think of objects starting with a fake alloc-id as having type 'payload'.
14122 # It's not really intended to be created dynamically; for that use `allocate`
14123 # as usual.
14124 #
14125 # Idea for a notation to simplify such definitions:
14126 #   _Primitive-increment-eax:  # (payload primitive)
14127 #     0x11/alloc-id:fake:payload
14128 #     0x11 @(0x11 "increment")  # name
14129 #     0 0                       # inouts
14130 #     0x11 @(0x11/payload
14131 #            0x11 @(0x11/payload  # List-value
14132 #                   0 0             # Var-name
14133 #                   0x11 @(0x11     # Var-type
14134 #                          1/is-atom
14135 #                          1/value 0/unused   # Tree-left
14136 #                          0 0                # Tree-right
14137 #                         )
14138 #                   1               # block-depth
14139 #                   0               # stack-offset
14140 #                   0x11 @(0x11 "eax")  # Var-register
14141 #                  )
14142 #            0 0)                 # List-next
14143 #     ...
14144 #     _Primitive-increment-ecx/imm32/next
14145 #   ...
14146 # Awfully complex and non-obvious. But also clearly signals there's something
14147 # to learn here, so may be worth trying.
14148 #
14149 # '@' is just an initial thought. Punctuation used so far in Mu: () * % # / "
14150 #
14151 # For now we'll continue to just use comments and manually ensure they stay up
14152 # to date.
14153 == data
14154 Primitives:  # (addr primitive)
14155 # - increment/decrement
14156 _Primitive-increment-eax:  # (addr primitive)
14157     # var/eax <- increment => 40/increment-eax
14158     0x11/imm32/alloc-id:fake
14159     _string-increment/imm32/name
14160     0/imm32/no-inouts
14161     0/imm32/no-inouts
14162     0x11/imm32/alloc-id:fake
14163     Single-int-var-in-eax/imm32/outputs
14164     0x11/imm32/alloc-id:fake
14165     _string_40_increment_eax/imm32/subx-name
14166     0/imm32/no-rm32
14167     0/imm32/no-r32
14168     0/imm32/no-imm32
14169     0/imm32/no-disp32
14170     0/imm32/output-is-write-only
14171     0x11/imm32/alloc-id:fake
14172     _Primitive-increment-ecx/imm32/next
14173 _Primitive-increment-ecx:  # (payload primitive)
14174     0x11/imm32/alloc-id:fake:payload
14175     # var/ecx <- increment => 41/increment-ecx
14176     0x11/imm32/alloc-id:fake
14177     _string-increment/imm32/name
14178     0/imm32/no-inouts
14179     0/imm32/no-inouts
14180     0x11/imm32/alloc-id:fake
14181     Single-int-var-in-ecx/imm32/outputs
14182     0x11/imm32/alloc-id:fake
14183     _string_41_increment_ecx/imm32/subx-name
14184     0/imm32/no-rm32
14185     0/imm32/no-r32
14186     0/imm32/no-imm32
14187     0/imm32/no-disp32
14188     0/imm32/output-is-write-only
14189     0x11/imm32/alloc-id:fake
14190     _Primitive-increment-edx/imm32/next
14191 _Primitive-increment-edx:  # (payload primitive)
14192     0x11/imm32/alloc-id:fake:payload
14193     # var/edx <- increment => 42/increment-edx
14194     0x11/imm32/alloc-id:fake
14195     _string-increment/imm32/name
14196     0/imm32/no-inouts
14197     0/imm32/no-inouts
14198     0x11/imm32/alloc-id:fake
14199     Single-int-var-in-edx/imm32/outputs
14200     0x11/imm32/alloc-id:fake
14201     _string_42_increment_edx/imm32/subx-name
14202     0/imm32/no-rm32
14203     0/imm32/no-r32
14204     0/imm32/no-imm32
14205     0/imm32/no-disp32
14206     0/imm32/output-is-write-only
14207     0x11/imm32/alloc-id:fake
14208     _Primitive-increment-ebx/imm32/next
14209 _Primitive-increment-ebx:  # (payload primitive)
14210     0x11/imm32/alloc-id:fake:payload
14211     # var/ebx <- increment => 43/increment-ebx
14212     0x11/imm32/alloc-id:fake
14213     _string-increment/imm32/name
14214     0/imm32/no-inouts
14215     0/imm32/no-inouts
14216     0x11/imm32/alloc-id:fake
14217     Single-int-var-in-ebx/imm32/outputs
14218     0x11/imm32/alloc-id:fake
14219     _string_43_increment_ebx/imm32/subx-name
14220     0/imm32/no-rm32
14221     0/imm32/no-r32
14222     0/imm32/no-imm32
14223     0/imm32/no-disp32
14224     0/imm32/output-is-write-only
14225     0x11/imm32/alloc-id:fake
14226     _Primitive-increment-esi/imm32/next
14227 _Primitive-increment-esi:  # (payload primitive)
14228     0x11/imm32/alloc-id:fake:payload
14229     # var/esi <- increment => 46/increment-esi
14230     0x11/imm32/alloc-id:fake
14231     _string-increment/imm32/name
14232     0/imm32/no-inouts
14233     0/imm32/no-inouts
14234     0x11/imm32/alloc-id:fake
14235     Single-int-var-in-esi/imm32/outputs
14236     0x11/imm32/alloc-id:fake
14237     _string_46_increment_esi/imm32/subx-name
14238     0/imm32/no-rm32
14239     0/imm32/no-r32
14240     0/imm32/no-imm32
14241     0/imm32/no-disp32
14242     0/imm32/output-is-write-only
14243     0x11/imm32/alloc-id:fake
14244     _Primitive-increment-edi/imm32/next
14245 _Primitive-increment-edi:  # (payload primitive)
14246     0x11/imm32/alloc-id:fake:payload
14247     # var/edi <- increment => 47/increment-edi
14248     0x11/imm32/alloc-id:fake
14249     _string-increment/imm32/name
14250     0/imm32/no-inouts
14251     0/imm32/no-inouts
14252     0x11/imm32/alloc-id:fake
14253     Single-int-var-in-edi/imm32/outputs
14254     0x11/imm32/alloc-id:fake
14255     _string_47_increment_edi/imm32/subx-name
14256     0/imm32/no-rm32
14257     0/imm32/no-r32
14258     0/imm32/no-imm32
14259     0/imm32/no-disp32
14260     0/imm32/output-is-write-only
14261     0x11/imm32/alloc-id:fake
14262     _Primitive-decrement-eax/imm32/next
14263 _Primitive-decrement-eax:  # (payload primitive)
14264     0x11/imm32/alloc-id:fake:payload
14265     # var/eax <- decrement => 48/decrement-eax
14266     0x11/imm32/alloc-id:fake
14267     _string-decrement/imm32/name
14268     0/imm32/no-inouts
14269     0/imm32/no-inouts
14270     0x11/imm32/alloc-id:fake
14271     Single-int-var-in-eax/imm32/outputs
14272     0x11/imm32/alloc-id:fake
14273     _string_48_decrement_eax/imm32/subx-name
14274     0/imm32/no-rm32
14275     0/imm32/no-r32
14276     0/imm32/no-imm32
14277     0/imm32/no-disp32
14278     0/imm32/output-is-write-only
14279     0x11/imm32/alloc-id:fake
14280     _Primitive-decrement-ecx/imm32/next
14281 _Primitive-decrement-ecx:  # (payload primitive)
14282     0x11/imm32/alloc-id:fake:payload
14283     # var/ecx <- decrement => 49/decrement-ecx
14284     0x11/imm32/alloc-id:fake
14285     _string-decrement/imm32/name
14286     0/imm32/no-inouts
14287     0/imm32/no-inouts
14288     0x11/imm32/alloc-id:fake
14289     Single-int-var-in-ecx/imm32/outputs
14290     0x11/imm32/alloc-id:fake
14291     _string_49_decrement_ecx/imm32/subx-name
14292     0/imm32/no-rm32
14293     0/imm32/no-r32
14294     0/imm32/no-imm32
14295     0/imm32/no-disp32
14296     0/imm32/output-is-write-only
14297     0x11/imm32/alloc-id:fake
14298     _Primitive-decrement-edx/imm32/next
14299 _Primitive-decrement-edx:  # (payload primitive)
14300     0x11/imm32/alloc-id:fake:payload
14301     # var/edx <- decrement => 4a/decrement-edx
14302     0x11/imm32/alloc-id:fake
14303     _string-decrement/imm32/name
14304     0/imm32/no-inouts
14305     0/imm32/no-inouts
14306     0x11/imm32/alloc-id:fake
14307     Single-int-var-in-edx/imm32/outputs
14308     0x11/imm32/alloc-id:fake
14309     _string_4a_decrement_edx/imm32/subx-name
14310     0/imm32/no-rm32
14311     0/imm32/no-r32
14312     0/imm32/no-imm32
14313     0/imm32/no-disp32
14314     0/imm32/output-is-write-only
14315     0x11/imm32/alloc-id:fake
14316     _Primitive-decrement-ebx/imm32/next
14317 _Primitive-decrement-ebx:  # (payload primitive)
14318     0x11/imm32/alloc-id:fake:payload
14319     # var/ebx <- decrement => 4b/decrement-ebx
14320     0x11/imm32/alloc-id:fake
14321     _string-decrement/imm32/name
14322     0/imm32/no-inouts
14323     0/imm32/no-inouts
14324     0x11/imm32/alloc-id:fake
14325     Single-int-var-in-ebx/imm32/outputs
14326     0x11/imm32/alloc-id:fake
14327     _string_4b_decrement_ebx/imm32/subx-name
14328     0/imm32/no-rm32
14329     0/imm32/no-r32
14330     0/imm32/no-imm32
14331     0/imm32/no-disp32
14332     0/imm32/output-is-write-only
14333     0x11/imm32/alloc-id:fake
14334     _Primitive-decrement-esi/imm32/next
14335 _Primitive-decrement-esi:  # (payload primitive)
14336     0x11/imm32/alloc-id:fake:payload
14337     # var/esi <- decrement => 4e/decrement-esi
14338     0x11/imm32/alloc-id:fake
14339     _string-decrement/imm32/name
14340     0/imm32/no-inouts
14341     0/imm32/no-inouts
14342     0x11/imm32/alloc-id:fake
14343     Single-int-var-in-esi/imm32/outputs
14344     0x11/imm32/alloc-id:fake
14345     _string_4e_decrement_esi/imm32/subx-name
14346     0/imm32/no-rm32
14347     0/imm32/no-r32
14348     0/imm32/no-imm32
14349     0/imm32/no-disp32
14350     0/imm32/output-is-write-only
14351     0x11/imm32/alloc-id:fake
14352     _Primitive-decrement-edi/imm32/next
14353 _Primitive-decrement-edi:  # (payload primitive)
14354     0x11/imm32/alloc-id:fake:payload
14355     # var/edi <- decrement => 4f/decrement-edi
14356     0x11/imm32/alloc-id:fake
14357     _string-decrement/imm32/name
14358     0/imm32/no-inouts
14359     0/imm32/no-inouts
14360     0x11/imm32/alloc-id:fake
14361     Single-int-var-in-edi/imm32/outputs
14362     0x11/imm32/alloc-id:fake
14363     _string_4f_decrement_edi/imm32/subx-name
14364     0/imm32/no-rm32
14365     0/imm32/no-r32
14366     0/imm32/no-imm32
14367     0/imm32/no-disp32
14368     0/imm32/output-is-write-only
14369     0x11/imm32/alloc-id:fake
14370     _Primitive-increment-mem/imm32/next
14371 _Primitive-increment-mem:  # (payload primitive)
14372     0x11/imm32/alloc-id:fake:payload
14373     # increment var => ff 0/subop/increment *(ebp+__)
14374     0x11/imm32/alloc-id:fake
14375     _string-increment/imm32/name
14376     0x11/imm32/alloc-id:fake
14377     Single-int-var-in-mem/imm32/inouts
14378     0/imm32/no-outputs
14379     0/imm32/no-outputs
14380     0x11/imm32/alloc-id:fake
14381     _string_ff_subop_increment/imm32/subx-name
14382     1/imm32/rm32-is-first-inout
14383     0/imm32/no-r32
14384     0/imm32/no-imm32
14385     0/imm32/no-disp32
14386     0/imm32/output-is-write-only
14387     0x11/imm32/alloc-id:fake
14388     _Primitive-increment-reg/imm32/next
14389 _Primitive-increment-reg:  # (payload primitive)
14390     0x11/imm32/alloc-id:fake:payload
14391     # var/reg <- increment => ff 0/subop/increment %__
14392     0x11/imm32/alloc-id:fake
14393     _string-increment/imm32/name
14394     0/imm32/no-inouts
14395     0/imm32/no-inouts
14396     0x11/imm32/alloc-id:fake
14397     Single-int-var-in-some-register/imm32/outputs
14398     0x11/imm32/alloc-id:fake
14399     _string_ff_subop_increment/imm32/subx-name
14400     3/imm32/rm32-is-first-output
14401     0/imm32/no-r32
14402     0/imm32/no-imm32
14403     0/imm32/no-disp32
14404     0/imm32/output-is-write-only
14405     0x11/imm32/alloc-id:fake
14406     _Primitive-decrement-mem/imm32/next
14407 _Primitive-decrement-mem:  # (payload primitive)
14408     0x11/imm32/alloc-id:fake:payload
14409     # decrement var => ff 1/subop/decrement *(ebp+__)
14410     0x11/imm32/alloc-id:fake
14411     _string-decrement/imm32/name
14412     0x11/imm32/alloc-id:fake
14413     Single-int-var-in-mem/imm32/inouts
14414     0/imm32/no-outputs
14415     0/imm32/no-outputs
14416     0x11/imm32/alloc-id:fake
14417     _string_ff_subop_decrement/imm32/subx-name
14418     1/imm32/rm32-is-first-inout
14419     0/imm32/no-r32
14420     0/imm32/no-imm32
14421     0/imm32/no-disp32
14422     0/imm32/output-is-write-only
14423     0x11/imm32/alloc-id:fake
14424     _Primitive-decrement-reg/imm32/next
14425 _Primitive-decrement-reg:  # (payload primitive)
14426     0x11/imm32/alloc-id:fake:payload
14427     # var/reg <- decrement => ff 1/subop/decrement %__
14428     0x11/imm32/alloc-id:fake
14429     _string-decrement/imm32/name
14430     0/imm32/no-inouts
14431     0/imm32/no-inouts
14432     0x11/imm32/alloc-id:fake
14433     Single-int-var-in-some-register/imm32/outputs
14434     0x11/imm32/alloc-id:fake
14435     _string_ff_subop_decrement/imm32/subx-name
14436     3/imm32/rm32-is-first-output
14437     0/imm32/no-r32
14438     0/imm32/no-imm32
14439     0/imm32/no-disp32
14440     0/imm32/output-is-write-only
14441     0x11/imm32/alloc-id:fake
14442     _Primitive-add-to-eax/imm32/next
14443 # - add
14444 _Primitive-add-to-eax:  # (payload primitive)
14445     0x11/imm32/alloc-id:fake:payload
14446     # var/eax <- add lit => 05/add-to-eax lit/imm32
14447     0x11/imm32/alloc-id:fake
14448     _string-add/imm32/name
14449     0x11/imm32/alloc-id:fake
14450     Single-lit-var/imm32/inouts
14451     0x11/imm32/alloc-id:fake
14452     Single-int-var-in-eax/imm32/outputs
14453     0x11/imm32/alloc-id:fake
14454     _string_05_add_to_eax/imm32/subx-name
14455     0/imm32/no-rm32
14456     0/imm32/no-r32
14457     1/imm32/imm32-is-first-inout
14458     0/imm32/no-disp32
14459     0/imm32/output-is-write-only
14460     0x11/imm32/alloc-id:fake
14461     _Primitive-add-reg-to-reg/imm32/next
14462 _Primitive-add-reg-to-reg:  # (payload primitive)
14463     0x11/imm32/alloc-id:fake:payload
14464     # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32
14465     0x11/imm32/alloc-id:fake
14466     _string-add/imm32/name
14467     0x11/imm32/alloc-id:fake
14468     Single-int-var-in-some-register/imm32/inouts
14469     0x11/imm32/alloc-id:fake
14470     Single-int-var-in-some-register/imm32/outputs
14471     0x11/imm32/alloc-id:fake
14472     _string_01_add_to/imm32/subx-name
14473     3/imm32/rm32-is-first-output
14474     1/imm32/r32-is-first-inout
14475     0/imm32/no-imm32
14476     0/imm32/no-disp32
14477     0/imm32/output-is-write-only
14478     0x11/imm32/alloc-id:fake
14479     _Primitive-add-reg-to-mem/imm32/next
14480 _Primitive-add-reg-to-mem:  # (payload primitive)
14481     0x11/imm32/alloc-id:fake:payload
14482     # add-to var1 var2/reg => 01/add-to var1 var2/r32
14483     0x11/imm32/alloc-id:fake
14484     _string-add-to/imm32/name
14485     0x11/imm32/alloc-id:fake
14486     Two-args-int-stack-int-reg/imm32/inouts
14487     0/imm32/no-outputs
14488     0/imm32/no-outputs
14489     0x11/imm32/alloc-id:fake
14490     _string_01_add_to/imm32/subx-name
14491     1/imm32/rm32-is-first-inout
14492     2/imm32/r32-is-second-inout
14493     0/imm32/no-imm32
14494     0/imm32/no-disp32
14495     0/imm32/output-is-write-only
14496     0x11/imm32/alloc-id:fake
14497     _Primitive-add-mem-to-reg/imm32/next
14498 _Primitive-add-mem-to-reg:  # (payload primitive)
14499     0x11/imm32/alloc-id:fake:payload
14500     # var1/reg <- add var2 => 03/add var2/rm32 var1/r32
14501     0x11/imm32/alloc-id:fake
14502     _string-add/imm32/name
14503     0x11/imm32/alloc-id:fake
14504     Single-int-var-in-mem/imm32/inouts
14505     0x11/imm32/alloc-id:fake
14506     Single-int-var-in-some-register/imm32/outputs
14507     0x11/imm32/alloc-id:fake
14508     _string_03_add/imm32/subx-name
14509     1/imm32/rm32-is-first-inout
14510     3/imm32/r32-is-first-output
14511     0/imm32/no-imm32
14512     0/imm32/no-disp32
14513     0/imm32/output-is-write-only
14514     0x11/imm32/alloc-id:fake
14515     _Primitive-add-lit-to-reg/imm32/next
14516 _Primitive-add-lit-to-reg:  # (payload primitive)
14517     0x11/imm32/alloc-id:fake:payload
14518     # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32
14519     0x11/imm32/alloc-id:fake
14520     _string-add/imm32/name
14521     0x11/imm32/alloc-id:fake
14522     Single-lit-var/imm32/inouts
14523     0x11/imm32/alloc-id:fake
14524     Single-int-var-in-some-register/imm32/outputs
14525     0x11/imm32/alloc-id:fake
14526     _string_81_subop_add/imm32/subx-name
14527     3/imm32/rm32-is-first-output
14528     0/imm32/no-r32
14529     1/imm32/imm32-is-first-inout
14530     0/imm32/no-disp32
14531     0/imm32/output-is-write-only
14532     0x11/imm32/alloc-id:fake
14533     _Primitive-add-lit-to-mem/imm32/next
14534 _Primitive-add-lit-to-mem:  # (payload primitive)
14535     0x11/imm32/alloc-id:fake:payload
14536     # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32
14537     0x11/imm32/alloc-id:fake
14538     _string-add-to/imm32/name
14539     0x11/imm32/alloc-id:fake
14540     Int-var-and-literal/imm32/inouts
14541     0/imm32/no-outputs
14542     0/imm32/no-outputs
14543     0x11/imm32/alloc-id:fake
14544     _string_81_subop_add/imm32/subx-name
14545     1/imm32/rm32-is-first-inout
14546     0/imm32/no-r32
14547     2/imm32/imm32-is-second-inout
14548     0/imm32/no-disp32
14549     0/imm32/output-is-write-only
14550     0x11/imm32/alloc-id:fake
14551     _Primitive-subtract-from-eax/imm32/next
14552 # - subtract
14553 _Primitive-subtract-from-eax:  # (payload primitive)
14554     0x11/imm32/alloc-id:fake:payload
14555     # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32
14556     0x11/imm32/alloc-id:fake
14557     _string-subtract/imm32/name
14558     0x11/imm32/alloc-id:fake
14559     Single-lit-var/imm32/inouts
14560     0x11/imm32/alloc-id:fake
14561     Single-int-var-in-eax/imm32/outputs
14562     0x11/imm32/alloc-id:fake
14563     _string_2d_subtract_from_eax/imm32/subx-name
14564     0/imm32/no-rm32
14565     0/imm32/no-r32
14566     1/imm32/imm32-is-first-inout
14567     0/imm32/no-disp32
14568     0/imm32/output-is-write-only
14569     0x11/imm32/alloc-id:fake
14570     _Primitive-subtract-reg-from-reg/imm32/next
14571 _Primitive-subtract-reg-from-reg:  # (payload primitive)
14572     0x11/imm32/alloc-id:fake:payload
14573     # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32
14574     0x11/imm32/alloc-id:fake
14575     _string-subtract/imm32/name
14576     0x11/imm32/alloc-id:fake
14577     Single-int-var-in-some-register/imm32/inouts
14578     0x11/imm32/alloc-id:fake
14579     Single-int-var-in-some-register/imm32/outputs
14580     0x11/imm32/alloc-id:fake
14581     _string_29_subtract_from/imm32/subx-name
14582     3/imm32/rm32-is-first-output
14583     1/imm32/r32-is-first-inout
14584     0/imm32/no-imm32
14585     0/imm32/no-disp32
14586     0/imm32/output-is-write-only
14587     0x11/imm32/alloc-id:fake
14588     _Primitive-subtract-reg-from-mem/imm32/next
14589 _Primitive-subtract-reg-from-mem:  # (payload primitive)
14590     0x11/imm32/alloc-id:fake:payload
14591     # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32
14592     0x11/imm32/alloc-id:fake
14593     _string-subtract-from/imm32/name
14594     0x11/imm32/alloc-id:fake
14595     Two-args-int-stack-int-reg/imm32/inouts
14596     0/imm32/no-outputs
14597     0/imm32/no-outputs
14598     0x11/imm32/alloc-id:fake
14599     _string_29_subtract_from/imm32/subx-name
14600     1/imm32/rm32-is-first-inout
14601     2/imm32/r32-is-second-inout
14602     0/imm32/no-imm32
14603     0/imm32/no-disp32
14604     0/imm32/output-is-write-only
14605     0x11/imm32/alloc-id:fake
14606     _Primitive-subtract-mem-from-reg/imm32/next
14607 _Primitive-subtract-mem-from-reg:  # (payload primitive)
14608     0x11/imm32/alloc-id:fake:payload
14609     # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32
14610     0x11/imm32/alloc-id:fake
14611     _string-subtract/imm32/name
14612     0x11/imm32/alloc-id:fake
14613     Single-int-var-in-mem/imm32/inouts
14614     0x11/imm32/alloc-id:fake
14615     Single-int-var-in-some-register/imm32/outputs
14616     0x11/imm32/alloc-id:fake
14617     _string_2b_subtract/imm32/subx-name
14618     1/imm32/rm32-is-first-inout
14619     3/imm32/r32-is-first-output
14620     0/imm32/no-imm32
14621     0/imm32/no-disp32
14622     0/imm32/output-is-write-only
14623     0x11/imm32/alloc-id:fake
14624     _Primitive-subtract-lit-from-reg/imm32/next
14625 _Primitive-subtract-lit-from-reg:  # (payload primitive)
14626     0x11/imm32/alloc-id:fake:payload
14627     # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32
14628     0x11/imm32/alloc-id:fake
14629     _string-subtract/imm32/name
14630     0x11/imm32/alloc-id:fake
14631     Single-lit-var/imm32/inouts
14632     0x11/imm32/alloc-id:fake
14633     Single-int-var-in-some-register/imm32/outputs
14634     0x11/imm32/alloc-id:fake
14635     _string_81_subop_subtract/imm32/subx-name
14636     3/imm32/rm32-is-first-output
14637     0/imm32/no-r32
14638     1/imm32/imm32-is-first-inout
14639     0/imm32/no-disp32
14640     0/imm32/output-is-write-only
14641     0x11/imm32/alloc-id:fake
14642     _Primitive-subtract-lit-from-mem/imm32/next
14643 _Primitive-subtract-lit-from-mem:  # (payload primitive)
14644     0x11/imm32/alloc-id:fake:payload
14645     # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32
14646     0x11/imm32/alloc-id:fake
14647     _string-subtract-from/imm32/name
14648     0x11/imm32/alloc-id:fake
14649     Int-var-and-literal/imm32/inouts
14650     0/imm32/no-outputs
14651     0/imm32/no-outputs
14652     0x11/imm32/alloc-id:fake
14653     _string_81_subop_subtract/imm32/subx-name
14654     1/imm32/rm32-is-first-inout
14655     0/imm32/no-r32
14656     2/imm32/imm32-is-first-inout
14657     0/imm32/no-disp32
14658     0/imm32/output-is-write-only
14659     0x11/imm32/alloc-id:fake
14660     _Primitive-and-with-eax/imm32/next
14661 # - and
14662 _Primitive-and-with-eax:  # (payload primitive)
14663     0x11/imm32/alloc-id:fake:payload
14664     # var/eax <- and lit => 25/and-with-eax lit/imm32
14665     0x11/imm32/alloc-id:fake
14666     _string-and/imm32/name
14667     0x11/imm32/alloc-id:fake
14668     Single-lit-var/imm32/inouts
14669     0x11/imm32/alloc-id:fake
14670     Single-int-var-in-eax/imm32/outputs
14671     0x11/imm32/alloc-id:fake
14672     _string_25_and_with_eax/imm32/subx-name
14673     0/imm32/no-rm32
14674     0/imm32/no-r32
14675     1/imm32/imm32-is-first-inout
14676     0/imm32/no-disp32
14677     0/imm32/output-is-write-only
14678     0x11/imm32/alloc-id:fake
14679     _Primitive-and-reg-with-reg/imm32/next
14680 _Primitive-and-reg-with-reg:  # (payload primitive)
14681     0x11/imm32/alloc-id:fake:payload
14682     # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32
14683     0x11/imm32/alloc-id:fake
14684     _string-and/imm32/name
14685     0x11/imm32/alloc-id:fake
14686     Single-int-var-in-some-register/imm32/inouts
14687     0x11/imm32/alloc-id:fake
14688     Single-int-var-in-some-register/imm32/outputs
14689     0x11/imm32/alloc-id:fake
14690     _string_21_and_with/imm32/subx-name
14691     3/imm32/rm32-is-first-output
14692     1/imm32/r32-is-first-inout
14693     0/imm32/no-imm32
14694     0/imm32/no-disp32
14695     0/imm32/output-is-write-only
14696     0x11/imm32/alloc-id:fake
14697     _Primitive-and-reg-with-mem/imm32/next
14698 _Primitive-and-reg-with-mem:  # (payload primitive)
14699     0x11/imm32/alloc-id:fake:payload
14700     # and-with var1 var2/reg => 21/and-with var1 var2/r32
14701     0x11/imm32/alloc-id:fake
14702     _string-and-with/imm32/name
14703     0x11/imm32/alloc-id:fake
14704     Two-args-int-stack-int-reg/imm32/inouts
14705     0/imm32/no-outputs
14706     0/imm32/no-outputs
14707     0x11/imm32/alloc-id:fake
14708     _string_21_and_with/imm32/subx-name
14709     1/imm32/rm32-is-first-inout
14710     2/imm32/r32-is-second-inout
14711     0/imm32/no-imm32
14712     0/imm32/no-disp32
14713     0/imm32/output-is-write-only
14714     0x11/imm32/alloc-id:fake
14715     _Primitive-and-mem-with-reg/imm32/next
14716 _Primitive-and-mem-with-reg:  # (payload primitive)
14717     0x11/imm32/alloc-id:fake:payload
14718     # var1/reg <- and var2 => 23/and var2/rm32 var1/r32
14719     0x11/imm32/alloc-id:fake
14720     _string-and/imm32/name
14721     0x11/imm32/alloc-id:fake
14722     Single-int-var-in-mem/imm32/inouts
14723     0x11/imm32/alloc-id:fake
14724     Single-int-var-in-some-register/imm32/outputs
14725     0x11/imm32/alloc-id:fake
14726     _string_23_and/imm32/subx-name
14727     1/imm32/rm32-is-first-inout
14728     3/imm32/r32-is-first-output
14729     0/imm32/no-imm32
14730     0/imm32/no-disp32
14731     0/imm32/output-is-write-only
14732     0x11/imm32/alloc-id:fake
14733     _Primitive-and-lit-with-reg/imm32/next
14734 _Primitive-and-lit-with-reg:  # (payload primitive)
14735     0x11/imm32/alloc-id:fake:payload
14736     # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32
14737     0x11/imm32/alloc-id:fake
14738     _string-and/imm32/name
14739     0x11/imm32/alloc-id:fake
14740     Single-lit-var/imm32/inouts
14741     0x11/imm32/alloc-id:fake
14742     Single-int-var-in-some-register/imm32/outputs
14743     0x11/imm32/alloc-id:fake
14744     _string_81_subop_and/imm32/subx-name
14745     3/imm32/rm32-is-first-output
14746     0/imm32/no-r32
14747     1/imm32/imm32-is-first-inout
14748     0/imm32/no-disp32
14749     0/imm32/output-is-write-only
14750     0x11/imm32/alloc-id:fake
14751     _Primitive-and-lit-with-mem/imm32/next
14752 _Primitive-and-lit-with-mem:  # (payload primitive)
14753     0x11/imm32/alloc-id:fake:payload
14754     # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32
14755     0x11/imm32/alloc-id:fake
14756     _string-and-with/imm32/name
14757     0x11/imm32/alloc-id:fake
14758     Int-var-and-literal/imm32/inouts
14759     0/imm32/no-outputs
14760     0/imm32/no-outputs
14761     0x11/imm32/alloc-id:fake
14762     _string_81_subop_and/imm32/subx-name
14763     1/imm32/rm32-is-first-inout
14764     0/imm32/no-r32
14765     2/imm32/imm32-is-first-inout
14766     0/imm32/no-disp32
14767     0/imm32/output-is-write-only
14768     0x11/imm32/alloc-id:fake
14769     _Primitive-or-with-eax/imm32/next
14770 # - or
14771 _Primitive-or-with-eax:  # (payload primitive)
14772     0x11/imm32/alloc-id:fake:payload
14773     # var/eax <- or lit => 0d/or-with-eax lit/imm32
14774     0x11/imm32/alloc-id:fake
14775     _string-or/imm32/name
14776     0x11/imm32/alloc-id:fake
14777     Single-lit-var/imm32/inouts
14778     0x11/imm32/alloc-id:fake
14779     Single-int-var-in-eax/imm32/outputs
14780     0x11/imm32/alloc-id:fake
14781     _string_0d_or_with_eax/imm32/subx-name
14782     0/imm32/no-rm32
14783     0/imm32/no-r32
14784     1/imm32/imm32-is-first-inout
14785     0/imm32/no-disp32
14786     0/imm32/output-is-write-only
14787     0x11/imm32/alloc-id:fake
14788     _Primitive-or-reg-with-reg/imm32/next
14789 _Primitive-or-reg-with-reg:  # (payload primitive)
14790     0x11/imm32/alloc-id:fake:payload
14791     # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32
14792     0x11/imm32/alloc-id:fake
14793     _string-or/imm32/name
14794     0x11/imm32/alloc-id:fake
14795     Single-int-var-in-some-register/imm32/inouts
14796     0x11/imm32/alloc-id:fake
14797     Single-int-var-in-some-register/imm32/outputs
14798     0x11/imm32/alloc-id:fake
14799     _string_09_or_with/imm32/subx-name
14800     3/imm32/rm32-is-first-output
14801     1/imm32/r32-is-first-inout
14802     0/imm32/no-imm32
14803     0/imm32/no-disp32
14804     0/imm32/output-is-write-only
14805     0x11/imm32/alloc-id:fake
14806     _Primitive-or-reg-with-mem/imm32/next
14807 _Primitive-or-reg-with-mem:  # (payload primitive)
14808     0x11/imm32/alloc-id:fake:payload
14809     # or-with var1 var2/reg => 09/or-with var1 var2/r32
14810     0x11/imm32/alloc-id:fake
14811     _string-or-with/imm32/name
14812     0x11/imm32/alloc-id:fake
14813     Two-args-int-stack-int-reg/imm32/inouts
14814     0/imm32/no-outputs
14815     0/imm32/no-outputs
14816     0x11/imm32/alloc-id:fake
14817     _string_09_or_with/imm32/subx-name
14818     1/imm32/rm32-is-first-inout
14819     2/imm32/r32-is-second-inout
14820     0/imm32/no-imm32
14821     0/imm32/no-disp32
14822     0/imm32/output-is-write-only
14823     0x11/imm32/alloc-id:fake
14824     _Primitive-or-mem-with-reg/imm32/next
14825 _Primitive-or-mem-with-reg:  # (payload primitive)
14826     0x11/imm32/alloc-id:fake:payload
14827     # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32
14828     0x11/imm32/alloc-id:fake
14829     _string-or/imm32/name
14830     0x11/imm32/alloc-id:fake
14831     Single-int-var-in-mem/imm32/inouts
14832     0x11/imm32/alloc-id:fake
14833     Single-int-var-in-some-register/imm32/outputs
14834     0x11/imm32/alloc-id:fake
14835     _string_0b_or/imm32/subx-name
14836     1/imm32/rm32-is-first-inout
14837     3/imm32/r32-is-first-output
14838     0/imm32/no-imm32
14839     0/imm32/no-disp32
14840     0/imm32/output-is-write-only
14841     0x11/imm32/alloc-id:fake
14842     _Primitive-or-lit-with-reg/imm32/next
14843 _Primitive-or-lit-with-reg:  # (payload primitive)
14844     0x11/imm32/alloc-id:fake:payload
14845     # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32
14846     0x11/imm32/alloc-id:fake
14847     _string-or/imm32/name
14848     0x11/imm32/alloc-id:fake
14849     Single-lit-var/imm32/inouts
14850     0x11/imm32/alloc-id:fake
14851     Single-int-var-in-some-register/imm32/outputs
14852     0x11/imm32/alloc-id:fake
14853     _string_81_subop_or/imm32/subx-name
14854     3/imm32/rm32-is-first-output
14855     0/imm32/no-r32
14856     1/imm32/imm32-is-first-inout
14857     0/imm32/no-disp32
14858     0/imm32/output-is-write-only
14859     0x11/imm32/alloc-id:fake
14860     _Primitive-or-lit-with-mem/imm32/next
14861 _Primitive-or-lit-with-mem:  # (payload primitive)
14862     0x11/imm32/alloc-id:fake:payload
14863     # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32
14864     0x11/imm32/alloc-id:fake
14865     _string-or-with/imm32/name
14866     0x11/imm32/alloc-id:fake
14867     Int-var-and-literal/imm32/inouts
14868     0/imm32/no-outputs
14869     0/imm32/no-outputs
14870     0x11/imm32/alloc-id:fake
14871     _string_81_subop_or/imm32/subx-name
14872     1/imm32/rm32-is-first-inout
14873     0/imm32/no-r32
14874     2/imm32/imm32-is-second-inout
14875     0/imm32/no-disp32
14876     0/imm32/output-is-write-only
14877     0x11/imm32/alloc-id:fake
14878     _Primitive-xor-with-eax/imm32/next
14879 # - xor
14880 _Primitive-xor-with-eax:  # (payload primitive)
14881     0x11/imm32/alloc-id:fake:payload
14882     # var/eax <- xor lit => 35/xor-with-eax lit/imm32
14883     0x11/imm32/alloc-id:fake
14884     _string-xor/imm32/name
14885     0x11/imm32/alloc-id:fake
14886     Single-lit-var/imm32/inouts
14887     0x11/imm32/alloc-id:fake
14888     Single-int-var-in-eax/imm32/outputs
14889     0x11/imm32/alloc-id:fake
14890     _string_35_xor_with_eax/imm32/subx-name
14891     0/imm32/no-rm32
14892     0/imm32/no-r32
14893     1/imm32/imm32-is-first-inout
14894     0/imm32/no-disp32
14895     0/imm32/output-is-write-only
14896     0x11/imm32/alloc-id:fake
14897     _Primitive-xor-reg-with-reg/imm32/next
14898 _Primitive-xor-reg-with-reg:  # (payload primitive)
14899     0x11/imm32/alloc-id:fake:payload
14900     # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32
14901     0x11/imm32/alloc-id:fake
14902     _string-xor/imm32/name
14903     0x11/imm32/alloc-id:fake
14904     Single-int-var-in-some-register/imm32/inouts
14905     0x11/imm32/alloc-id:fake
14906     Single-int-var-in-some-register/imm32/outputs
14907     0x11/imm32/alloc-id:fake
14908     _string_31_xor_with/imm32/subx-name
14909     3/imm32/rm32-is-first-output
14910     1/imm32/r32-is-first-inout
14911     0/imm32/no-imm32
14912     0/imm32/no-disp32
14913     0/imm32/output-is-write-only
14914     0x11/imm32/alloc-id:fake
14915     _Primitive-xor-reg-with-mem/imm32/next
14916 _Primitive-xor-reg-with-mem:  # (payload primitive)
14917     0x11/imm32/alloc-id:fake:payload
14918     # xor-with var1 var2/reg => 31/xor-with var1 var2/r32
14919     0x11/imm32/alloc-id:fake
14920     _string-xor-with/imm32/name
14921     0x11/imm32/alloc-id:fake
14922     Two-args-int-stack-int-reg/imm32/inouts
14923     0/imm32/no-outputs
14924     0/imm32/no-outputs
14925     0x11/imm32/alloc-id:fake
14926     _string_31_xor_with/imm32/subx-name
14927     1/imm32/rm32-is-first-inout
14928     2/imm32/r32-is-second-inout
14929     0/imm32/no-imm32
14930     0/imm32/no-disp32
14931     0/imm32/output-is-write-only
14932     0x11/imm32/alloc-id:fake
14933     _Primitive-xor-mem-with-reg/imm32/next
14934 _Primitive-xor-mem-with-reg:  # (payload primitive)
14935     0x11/imm32/alloc-id:fake:payload
14936     # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32
14937     0x11/imm32/alloc-id:fake
14938     _string-xor/imm32/name
14939     0x11/imm32/alloc-id:fake
14940     Single-int-var-in-mem/imm32/inouts
14941     0x11/imm32/alloc-id:fake
14942     Single-int-var-in-some-register/imm32/outputs
14943     0x11/imm32/alloc-id:fake
14944     _string_33_xor/imm32/subx-name
14945     1/imm32/rm32-is-first-inout
14946     3/imm32/r32-is-first-output
14947     0/imm32/no-imm32
14948     0/imm32/no-disp32
14949     0/imm32/output-is-write-only
14950     0x11/imm32/alloc-id:fake
14951     _Primitive-xor-lit-with-reg/imm32/next
14952 _Primitive-xor-lit-with-reg:  # (payload primitive)
14953     0x11/imm32/alloc-id:fake:payload
14954     # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32
14955     0x11/imm32/alloc-id:fake
14956     _string-xor/imm32/name
14957     0x11/imm32/alloc-id:fake
14958     Single-lit-var/imm32/inouts
14959     0x11/imm32/alloc-id:fake
14960     Single-int-var-in-some-register/imm32/outputs
14961     0x11/imm32/alloc-id:fake
14962     _string_81_subop_xor/imm32/subx-name
14963     3/imm32/rm32-is-first-output
14964     0/imm32/no-r32
14965     1/imm32/imm32-is-first-inout
14966     0/imm32/no-disp32
14967     0/imm32/output-is-write-only
14968     0x11/imm32/alloc-id:fake
14969     _Primitive-xor-lit-with-mem/imm32/next
14970 _Primitive-xor-lit-with-mem:  # (payload primitive)
14971     0x11/imm32/alloc-id:fake:payload
14972     # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32
14973     0x11/imm32/alloc-id:fake
14974     _string-xor-with/imm32/name
14975     0x11/imm32/alloc-id:fake
14976     Int-var-and-literal/imm32/inouts
14977     0/imm32/no-outputs
14978     0/imm32/no-outputs
14979     0x11/imm32/alloc-id:fake
14980     _string_81_subop_xor/imm32/subx-name
14981     1/imm32/rm32-is-first-inout
14982     0/imm32/no-r32
14983     2/imm32/imm32-is-first-inout
14984     0/imm32/no-disp32
14985     0/imm32/output-is-write-only
14986     0x11/imm32/alloc-id:fake
14987     _Primitive-copy-to-eax/imm32/next
14988 # - copy
14989 _Primitive-copy-to-eax:  # (payload primitive)
14990     0x11/imm32/alloc-id:fake:payload
14991     # var/eax <- copy lit => b8/copy-to-eax lit/imm32
14992     0x11/imm32/alloc-id:fake
14993     _string-copy/imm32/name
14994     0x11/imm32/alloc-id:fake
14995     Single-lit-var/imm32/inouts
14996     0x11/imm32/alloc-id:fake
14997     Single-int-var-in-eax/imm32/outputs
14998     0x11/imm32/alloc-id:fake
14999     _string_b8_copy_to_eax/imm32/subx-name
15000     0/imm32/no-rm32
15001     0/imm32/no-r32
15002     1/imm32/imm32-is-first-inout
15003     0/imm32/no-disp32
15004     1/imm32/output-is-write-only
15005     0x11/imm32/alloc-id:fake
15006     _Primitive-copy-to-ecx/imm32/next
15007 _Primitive-copy-to-ecx:  # (payload primitive)
15008     0x11/imm32/alloc-id:fake:payload
15009     # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32
15010     0x11/imm32/alloc-id:fake
15011     _string-copy/imm32/name
15012     0x11/imm32/alloc-id:fake
15013     Single-lit-var/imm32/inouts
15014     0x11/imm32/alloc-id:fake
15015     Single-int-var-in-ecx/imm32/outputs
15016     0x11/imm32/alloc-id:fake
15017     _string_b9_copy_to_ecx/imm32/subx-name
15018     0/imm32/no-rm32
15019     0/imm32/no-r32
15020     1/imm32/imm32-is-first-inout
15021     0/imm32/no-disp32
15022     1/imm32/output-is-write-only
15023     0x11/imm32/alloc-id:fake
15024     _Primitive-copy-to-edx/imm32/next
15025 _Primitive-copy-to-edx:  # (payload primitive)
15026     0x11/imm32/alloc-id:fake:payload
15027     # var/edx <- copy lit => ba/copy-to-edx lit/imm32
15028     0x11/imm32/alloc-id:fake
15029     _string-copy/imm32/name
15030     0x11/imm32/alloc-id:fake
15031     Single-lit-var/imm32/inouts
15032     0x11/imm32/alloc-id:fake
15033     Single-int-var-in-edx/imm32/outputs
15034     0x11/imm32/alloc-id:fake
15035     _string_ba_copy_to_edx/imm32/subx-name
15036     0/imm32/no-rm32
15037     0/imm32/no-r32
15038     1/imm32/imm32-is-first-inout
15039     0/imm32/no-disp32
15040     1/imm32/output-is-write-only
15041     0x11/imm32/alloc-id:fake
15042     _Primitive-copy-to-ebx/imm32/next
15043 _Primitive-copy-to-ebx:  # (payload primitive)
15044     0x11/imm32/alloc-id:fake:payload
15045     # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32
15046     0x11/imm32/alloc-id:fake
15047     _string-copy/imm32/name
15048     0x11/imm32/alloc-id:fake
15049     Single-lit-var/imm32/inouts
15050     0x11/imm32/alloc-id:fake
15051     Single-int-var-in-ebx/imm32/outputs
15052     0x11/imm32/alloc-id:fake
15053     _string_bb_copy_to_ebx/imm32/subx-name
15054     0/imm32/no-rm32
15055     0/imm32/no-r32
15056     1/imm32/imm32-is-first-inout
15057     0/imm32/no-disp32
15058     1/imm32/output-is-write-only
15059     0x11/imm32/alloc-id:fake
15060     _Primitive-copy-to-esi/imm32/next
15061 _Primitive-copy-to-esi:  # (payload primitive)
15062     0x11/imm32/alloc-id:fake:payload
15063     # var/esi <- copy lit => be/copy-to-esi lit/imm32
15064     0x11/imm32/alloc-id:fake
15065     _string-copy/imm32/name
15066     0x11/imm32/alloc-id:fake
15067     Single-lit-var/imm32/inouts
15068     0x11/imm32/alloc-id:fake
15069     Single-int-var-in-esi/imm32/outputs
15070     0x11/imm32/alloc-id:fake
15071     _string_be_copy_to_esi/imm32/subx-name
15072     0/imm32/no-rm32
15073     0/imm32/no-r32
15074     1/imm32/imm32-is-first-inout
15075     0/imm32/no-disp32
15076     1/imm32/output-is-write-only
15077     0x11/imm32/alloc-id:fake
15078     _Primitive-copy-to-edi/imm32/next
15079 _Primitive-copy-to-edi:  # (payload primitive)
15080     0x11/imm32/alloc-id:fake:payload
15081     # var/edi <- copy lit => bf/copy-to-edi lit/imm32
15082     0x11/imm32/alloc-id:fake
15083     _string-copy/imm32/name
15084     0x11/imm32/alloc-id:fake
15085     Single-lit-var/imm32/inouts
15086     0x11/imm32/alloc-id:fake
15087     Single-int-var-in-edi/imm32/outputs
15088     0x11/imm32/alloc-id:fake
15089     _string_bf_copy_to_edi/imm32/subx-name
15090     0/imm32/no-rm32
15091     0/imm32/no-r32
15092     1/imm32/imm32-is-first-inout
15093     0/imm32/no-disp32
15094     1/imm32/output-is-write-only
15095     0x11/imm32/alloc-id:fake
15096     _Primitive-copy-reg-to-reg/imm32/next
15097 _Primitive-copy-reg-to-reg:  # (payload primitive)
15098     0x11/imm32/alloc-id:fake:payload
15099     # var1/reg <- copy var2/reg => 89/<- var1/rm32 var2/r32
15100     0x11/imm32/alloc-id:fake
15101     _string-copy/imm32/name
15102     0x11/imm32/alloc-id:fake
15103     Single-int-var-in-some-register/imm32/inouts
15104     0x11/imm32/alloc-id:fake
15105     Single-int-var-in-some-register/imm32/outputs
15106     0x11/imm32/alloc-id:fake
15107     _string_89_<-/imm32/subx-name
15108     3/imm32/rm32-is-first-output
15109     1/imm32/r32-is-first-inout
15110     0/imm32/no-imm32
15111     0/imm32/no-disp32
15112     1/imm32/output-is-write-only
15113     0x11/imm32/alloc-id:fake
15114     _Primitive-copy-reg-to-mem/imm32/next
15115 _Primitive-copy-reg-to-mem:  # (payload primitive)
15116     0x11/imm32/alloc-id:fake:payload
15117     # copy-to var1 var2/reg => 89/<- var1 var2/r32
15118     0x11/imm32/alloc-id:fake
15119     _string-copy-to/imm32/name
15120     0x11/imm32/alloc-id:fake
15121     Two-args-int-stack-int-reg/imm32/inouts
15122     0/imm32/no-outputs
15123     0/imm32/no-outputs
15124     0x11/imm32/alloc-id:fake
15125     _string_89_<-/imm32/subx-name
15126     1/imm32/rm32-is-first-inout
15127     2/imm32/r32-is-second-inout
15128     0/imm32/no-imm32
15129     0/imm32/no-disp32
15130     1/imm32/output-is-write-only
15131     0x11/imm32/alloc-id:fake
15132     _Primitive-copy-mem-to-reg/imm32/next
15133 _Primitive-copy-mem-to-reg:  # (payload primitive)
15134     0x11/imm32/alloc-id:fake:payload
15135     # var1/reg <- copy var2 => 8b/-> var2/rm32 var1/r32
15136     0x11/imm32/alloc-id:fake
15137     _string-copy/imm32/name
15138     0x11/imm32/alloc-id:fake
15139     Single-int-var-in-mem/imm32/inouts
15140     0x11/imm32/alloc-id:fake
15141     Single-int-var-in-some-register/imm32/outputs
15142     0x11/imm32/alloc-id:fake
15143     _string_8b_->/imm32/subx-name
15144     1/imm32/rm32-is-first-inout
15145     3/imm32/r32-is-first-output
15146     0/imm32/no-imm32
15147     0/imm32/no-disp32
15148     1/imm32/output-is-write-only
15149     0x11/imm32/alloc-id:fake
15150     _Primitive-copy-lit-to-reg/imm32/next
15151 _Primitive-copy-lit-to-reg:  # (payload primitive)
15152     0x11/imm32/alloc-id:fake:payload
15153     # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32
15154     0x11/imm32/alloc-id:fake
15155     _string-copy/imm32/name
15156     0x11/imm32/alloc-id:fake
15157     Single-lit-var/imm32/inouts
15158     0x11/imm32/alloc-id:fake
15159     Single-int-var-in-some-register/imm32/outputs
15160     0x11/imm32/alloc-id:fake
15161     _string_c7_subop_copy/imm32/subx-name
15162     3/imm32/rm32-is-first-output
15163     0/imm32/no-r32
15164     1/imm32/imm32-is-first-inout
15165     0/imm32/no-disp32
15166     1/imm32/output-is-write-only
15167     0x11/imm32/alloc-id:fake
15168     _Primitive-copy-lit-to-mem/imm32/next
15169 _Primitive-copy-lit-to-mem:  # (payload primitive)
15170     0x11/imm32/alloc-id:fake:payload
15171     # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32
15172     0x11/imm32/alloc-id:fake
15173     _string-copy-to/imm32/name
15174     0x11/imm32/alloc-id:fake
15175     Int-var-and-literal/imm32/inouts
15176     0/imm32/no-outputs
15177     0/imm32/no-outputs
15178     0x11/imm32/alloc-id:fake
15179     _string_c7_subop_copy/imm32/subx-name
15180     1/imm32/rm32-is-first-inout
15181     0/imm32/no-r32
15182     2/imm32/imm32-is-first-inout
15183     0/imm32/no-disp32
15184     1/imm32/output-is-write-only
15185     0x11/imm32/alloc-id:fake
15186     _Primitive-copy-byte-from-reg/imm32/next
15187 # - copy byte
15188 _Primitive-copy-byte-from-reg:
15189     0x11/imm32/alloc-id:fake:payload
15190     # var/reg <- copy-byte var2/reg2 => 8a/byte-> %var2 var/r32
15191     0x11/imm32/alloc-id:fake
15192     _string-copy-byte/imm32/name
15193     0x11/imm32/alloc-id:fake
15194     Single-byte-var-in-some-register/imm32/inouts
15195     0x11/imm32/alloc-id:fake
15196     Single-byte-var-in-some-register/imm32/outputs
15197     0x11/imm32/alloc-id:fake
15198     _string_8a_copy_byte/imm32/subx-name
15199     1/imm32/rm32-is-first-inout
15200     3/imm32/r32-is-first-output
15201     0/imm32/no-imm32
15202     0/imm32/no-disp32
15203     1/imm32/output-is-write-only
15204     0x11/imm32/alloc-id:fake
15205     _Primitive-copy-byte-from-mem/imm32/next
15206 _Primitive-copy-byte-from-mem:
15207     0x11/imm32/alloc-id:fake:payload
15208     # var/reg <- copy-byte *var2/reg2 => 8a/byte-> *var2 var/r32
15209     0x11/imm32/alloc-id:fake
15210     _string-copy-byte/imm32/name
15211     0x11/imm32/alloc-id:fake
15212     Single-byte-var-in-mem/imm32/inouts
15213     0x11/imm32/alloc-id:fake
15214     Single-byte-var-in-some-register/imm32/outputs
15215     0x11/imm32/alloc-id:fake
15216     _string_8a_copy_byte/imm32/subx-name
15217     1/imm32/rm32-is-first-inout
15218     3/imm32/r32-is-first-output
15219     0/imm32/no-imm32
15220     0/imm32/no-disp32
15221     1/imm32/output-is-write-only
15222     0x11/imm32/alloc-id:fake
15223     _Primitive-copy-byte-to-mem/imm32/next
15224 _Primitive-copy-byte-to-mem:
15225     0x11/imm32/alloc-id:fake:payload
15226     # copy-byte-to *var1/reg1, var2/reg2 => 88/byte<- *reg1 reg2/r32
15227     0x11/imm32/alloc-id:fake
15228     _string-copy-byte-to/imm32/name
15229     0x11/imm32/alloc-id:fake
15230     Two-args-byte-stack-byte-reg/imm32/inouts
15231     0/imm32/no-outputs
15232     0/imm32/no-outputs
15233     0x11/imm32/alloc-id:fake
15234     _string_88_copy_byte/imm32/subx-name
15235     1/imm32/rm32-is-first-inout
15236     2/imm32/r32-is-second-inout
15237     0/imm32/no-imm32
15238     0/imm32/no-disp32
15239     0/imm32/output-is-write-only
15240     0x11/imm32/alloc-id:fake
15241     _Primitive-address/imm32/next
15242 # - address
15243 _Primitive-address:  # (payload primitive)
15244     0x11/imm32/alloc-id:fake:payload
15245     # var1/reg <- address var2 => 8d/copy-address var2/rm32 var1/r32
15246     0x11/imm32/alloc-id:fake
15247     _string-address/imm32/name
15248     0x11/imm32/alloc-id:fake
15249     Single-int-var-in-mem/imm32/inouts
15250     0x11/imm32/alloc-id:fake
15251     Single-addr-var-in-some-register/imm32/outputs
15252     0x11/imm32/alloc-id:fake
15253     _string_8d_copy_address/imm32/subx-name
15254     1/imm32/rm32-is-first-inout
15255     3/imm32/r32-is-first-output
15256     0/imm32/no-imm32
15257     0/imm32/no-disp32
15258     1/imm32/output-is-write-only
15259     0x11/imm32/alloc-id:fake
15260     _Primitive-compare-reg-with-reg/imm32/next
15261 # - compare
15262 _Primitive-compare-reg-with-reg:  # (payload primitive)
15263     0x11/imm32/alloc-id:fake:payload
15264     # compare var1/reg1 var2/reg2 => 39/compare var1/rm32 var2/r32
15265     0x11/imm32/alloc-id:fake
15266     _string-compare/imm32/name
15267     0x11/imm32/alloc-id:fake
15268     Two-int-args-in-regs/imm32/inouts
15269     0/imm32/no-outputs
15270     0/imm32/no-outputs
15271     0x11/imm32/alloc-id:fake
15272     _string_39_compare->/imm32/subx-name
15273     1/imm32/rm32-is-first-inout
15274     2/imm32/r32-is-second-inout
15275     0/imm32/no-imm32
15276     0/imm32/no-disp32
15277     0/imm32/output-is-write-only
15278     0x11/imm32/alloc-id:fake
15279     _Primitive-compare-mem-with-reg/imm32/next
15280 _Primitive-compare-mem-with-reg:  # (payload primitive)
15281     0x11/imm32/alloc-id:fake:payload
15282     # compare var1 var2/reg => 39/compare var1/rm32 var2/r32
15283     0x11/imm32/alloc-id:fake
15284     _string-compare/imm32/name
15285     0x11/imm32/alloc-id:fake
15286     Two-args-int-stack-int-reg/imm32/inouts
15287     0/imm32/no-outputs
15288     0/imm32/no-outputs
15289     0x11/imm32/alloc-id:fake
15290     _string_39_compare->/imm32/subx-name
15291     1/imm32/rm32-is-first-inout
15292     2/imm32/r32-is-second-inout
15293     0/imm32/no-imm32
15294     0/imm32/no-disp32
15295     0/imm32/output-is-write-only
15296     0x11/imm32/alloc-id:fake
15297     _Primitive-compare-reg-with-mem/imm32/next
15298 _Primitive-compare-reg-with-mem:  # (payload primitive)
15299     0x11/imm32/alloc-id:fake:payload
15300     # compare var1/reg var2 => 3b/compare<- var2/rm32 var1/r32
15301     0x11/imm32/alloc-id:fake
15302     _string-compare/imm32/name
15303     0x11/imm32/alloc-id:fake
15304     Two-args-int-reg-int-stack/imm32/inouts
15305     0/imm32/no-outputs
15306     0/imm32/no-outputs
15307     0x11/imm32/alloc-id:fake
15308     _string_3b_compare<-/imm32/subx-name
15309     2/imm32/rm32-is-second-inout
15310     1/imm32/r32-is-first-inout
15311     0/imm32/no-imm32
15312     0/imm32/no-disp32
15313     0/imm32/output-is-write-only
15314     0x11/imm32/alloc-id:fake
15315     _Primitive-compare-eax-with-literal/imm32/next
15316 _Primitive-compare-eax-with-literal:  # (payload primitive)
15317     0x11/imm32/alloc-id:fake:payload
15318     # compare var1/eax n => 3d/compare-eax-with n/imm32
15319     0x11/imm32/alloc-id:fake
15320     _string-compare/imm32/name
15321     0x11/imm32/alloc-id:fake
15322     Two-args-int-eax-int-literal/imm32/inouts
15323     0/imm32/no-outputs
15324     0/imm32/no-outputs
15325     0x11/imm32/alloc-id:fake
15326     _string_3d_compare_eax_with/imm32/subx-name
15327     0/imm32/no-rm32
15328     0/imm32/no-r32
15329     2/imm32/imm32-is-second-inout
15330     0/imm32/no-disp32
15331     0/imm32/output-is-write-only
15332     0x11/imm32/alloc-id:fake
15333     _Primitive-compare-reg-with-literal/imm32/next
15334 _Primitive-compare-reg-with-literal:  # (payload primitive)
15335     0x11/imm32/alloc-id:fake:payload
15336     # compare var1/reg n => 81 7/subop/compare %reg n/imm32
15337     0x11/imm32/alloc-id:fake
15338     _string-compare/imm32/name
15339     0x11/imm32/alloc-id:fake
15340     Int-var-in-register-and-literal/imm32/inouts
15341     0/imm32/no-outputs
15342     0/imm32/no-outputs
15343     0x11/imm32/alloc-id:fake
15344     _string_81_subop_compare/imm32/subx-name
15345     1/imm32/rm32-is-first-inout
15346     0/imm32/no-r32
15347     2/imm32/imm32-is-second-inout
15348     0/imm32/no-disp32
15349     0/imm32/output-is-write-only
15350     0x11/imm32/alloc-id:fake
15351     _Primitive-compare-mem-with-literal/imm32/next
15352 _Primitive-compare-mem-with-literal:  # (payload primitive)
15353     0x11/imm32/alloc-id:fake:payload
15354     # compare var1 n => 81 7/subop/compare *(ebp+___) n/imm32
15355     0x11/imm32/alloc-id:fake
15356     _string-compare/imm32/name
15357     0x11/imm32/alloc-id:fake
15358     Int-var-and-literal/imm32/inouts
15359     0/imm32/no-outputs
15360     0/imm32/no-outputs
15361     0x11/imm32/alloc-id:fake
15362     _string_81_subop_compare/imm32/subx-name
15363     1/imm32/rm32-is-first-inout
15364     0/imm32/no-r32
15365     2/imm32/imm32-is-second-inout
15366     0/imm32/no-disp32
15367     0/imm32/output-is-write-only
15368     0x11/imm32/alloc-id:fake
15369     _Primitive-multiply-reg-by-reg/imm32/next
15370 # - multiply
15371 _Primitive-multiply-reg-by-reg:  # (payload primitive)
15372     0x11/imm32/alloc-id:fake:payload
15373     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
15374     0x11/imm32/alloc-id:fake
15375     _string-multiply/imm32/name
15376     0x11/imm32/alloc-id:fake
15377     Single-int-var-in-some-register/imm32/inouts
15378     0x11/imm32/alloc-id:fake
15379     Single-int-var-in-some-register/imm32/outputs
15380     0x11/imm32/alloc-id:fake
15381     _string_0f_af_multiply/imm32/subx-name
15382     1/imm32/rm32-is-first-inout
15383     3/imm32/r32-is-first-output
15384     0/imm32/no-imm32
15385     0/imm32/no-disp32
15386     0/imm32/output-is-write-only
15387     0x11/imm32/alloc-id:fake
15388     _Primitive-multiply-reg-by-mem/imm32/next
15389 _Primitive-multiply-reg-by-mem:  # (payload primitive)
15390     0x11/imm32/alloc-id:fake:payload
15391     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
15392     0x11/imm32/alloc-id:fake
15393     _string-multiply/imm32/name
15394     0x11/imm32/alloc-id:fake
15395     Single-int-var-in-mem/imm32/inouts
15396     0x11/imm32/alloc-id:fake
15397     Single-int-var-in-some-register/imm32/outputs
15398     0x11/imm32/alloc-id:fake
15399     _string_0f_af_multiply/imm32/subx-name
15400     1/imm32/rm32-is-first-inout
15401     3/imm32/r32-is-first-output
15402     0/imm32/no-imm32
15403     0/imm32/no-disp32
15404     0/imm32/output-is-write-only
15405     0x11/imm32/alloc-id:fake
15406     _Primitive-break-if-addr</imm32/next
15407 # - branches
15408 _Primitive-break-if-addr<:  # (payload primitive)
15409     0x11/imm32/alloc-id:fake:payload
15410     0x11/imm32/alloc-id:fake
15411     _string-break-if-addr</imm32/name
15412     0/imm32/no-inouts
15413     0/imm32/no-inouts
15414     0/imm32/no-outputs
15415     0/imm32/no-outputs
15416     0x11/imm32/alloc-id:fake
15417     _string_0f_82_jump_break/imm32/subx-name
15418     0/imm32/no-rm32
15419     0/imm32/no-r32
15420     0/imm32/no-imm32
15421     0/imm32/no-disp32
15422     0/imm32/no-output
15423     0x11/imm32/alloc-id:fake
15424     _Primitive-break-if-addr>=/imm32/next
15425 _Primitive-break-if-addr>=:  # (payload primitive)
15426     0x11/imm32/alloc-id:fake:payload
15427     0x11/imm32/alloc-id:fake
15428     _string-break-if-addr>=/imm32/name
15429     0/imm32/no-inouts
15430     0/imm32/no-inouts
15431     0/imm32/no-outputs
15432     0/imm32/no-outputs
15433     0x11/imm32/alloc-id:fake
15434     _string_0f_83_jump_break/imm32/subx-name
15435     0/imm32/no-rm32
15436     0/imm32/no-r32
15437     0/imm32/no-imm32
15438     0/imm32/no-disp32
15439     0/imm32/no-output
15440     0x11/imm32/alloc-id:fake
15441     _Primitive-break-if-=/imm32/next
15442 _Primitive-break-if-=:  # (payload primitive)
15443     0x11/imm32/alloc-id:fake:payload
15444     0x11/imm32/alloc-id:fake
15445     _string-break-if-=/imm32/name
15446     0/imm32/no-inouts
15447     0/imm32/no-inouts
15448     0/imm32/no-outputs
15449     0/imm32/no-outputs
15450     0x11/imm32/alloc-id:fake
15451     _string_0f_84_jump_break/imm32/subx-name
15452     0/imm32/no-rm32
15453     0/imm32/no-r32
15454     0/imm32/no-imm32
15455     0/imm32/no-disp32
15456     0/imm32/no-output
15457     0x11/imm32/alloc-id:fake
15458     _Primitive-break-if-!=/imm32/next
15459 _Primitive-break-if-!=:  # (payload primitive)
15460     0x11/imm32/alloc-id:fake:payload
15461     0x11/imm32/alloc-id:fake
15462     _string-break-if-!=/imm32/name
15463     0/imm32/no-inouts
15464     0/imm32/no-inouts
15465     0/imm32/no-outputs
15466     0/imm32/no-outputs
15467     0x11/imm32/alloc-id:fake
15468     _string_0f_85_jump_break/imm32/subx-name
15469     0/imm32/no-rm32
15470     0/imm32/no-r32
15471     0/imm32/no-imm32
15472     0/imm32/no-disp32
15473     0/imm32/no-output
15474     0x11/imm32/alloc-id:fake
15475     _Primitive-break-if-addr<=/imm32/next
15476 _Primitive-break-if-addr<=:  # (payload primitive)
15477     0x11/imm32/alloc-id:fake:payload
15478     0x11/imm32/alloc-id:fake
15479     _string-break-if-addr<=/imm32/name
15480     0/imm32/no-inouts
15481     0/imm32/no-inouts
15482     0/imm32/no-outputs
15483     0/imm32/no-outputs
15484     0x11/imm32/alloc-id:fake
15485     _string_0f_86_jump_break/imm32/subx-name
15486     0/imm32/no-rm32
15487     0/imm32/no-r32
15488     0/imm32/no-imm32
15489     0/imm32/no-disp32
15490     0/imm32/no-output
15491     0x11/imm32/alloc-id:fake
15492     _Primitive-break-if-addr>/imm32/next
15493 _Primitive-break-if-addr>:  # (payload primitive)
15494     0x11/imm32/alloc-id:fake:payload
15495     0x11/imm32/alloc-id:fake
15496     _string-break-if-addr>/imm32/name
15497     0/imm32/no-inouts
15498     0/imm32/no-inouts
15499     0/imm32/no-outputs
15500     0/imm32/no-outputs
15501     0x11/imm32/alloc-id:fake
15502     _string_0f_87_jump_break/imm32/subx-name
15503     0/imm32/no-rm32
15504     0/imm32/no-r32
15505     0/imm32/no-imm32
15506     0/imm32/no-disp32
15507     0/imm32/no-output
15508     0x11/imm32/alloc-id:fake
15509     _Primitive-break-if-</imm32/next
15510 _Primitive-break-if-<:  # (payload primitive)
15511     0x11/imm32/alloc-id:fake:payload
15512     0x11/imm32/alloc-id:fake
15513     _string-break-if-</imm32/name
15514     0/imm32/no-inouts
15515     0/imm32/no-inouts
15516     0/imm32/no-outputs
15517     0/imm32/no-outputs
15518     0x11/imm32/alloc-id:fake
15519     _string_0f_8c_jump_break/imm32/subx-name
15520     0/imm32/no-rm32
15521     0/imm32/no-r32
15522     0/imm32/no-imm32
15523     0/imm32/no-disp32
15524     0/imm32/no-output
15525     0x11/imm32/alloc-id:fake
15526     _Primitive-break-if->=/imm32/next
15527 _Primitive-break-if->=:  # (payload primitive)
15528     0x11/imm32/alloc-id:fake:payload
15529     0x11/imm32/alloc-id:fake
15530     _string-break-if->=/imm32/name
15531     0/imm32/no-inouts
15532     0/imm32/no-inouts
15533     0/imm32/no-outputs
15534     0/imm32/no-outputs
15535     0x11/imm32/alloc-id:fake
15536     _string_0f_8d_jump_break/imm32/subx-name
15537     0/imm32/no-rm32
15538     0/imm32/no-r32
15539     0/imm32/no-imm32
15540     0/imm32/no-disp32
15541     0/imm32/no-output
15542     0x11/imm32/alloc-id:fake
15543     _Primitive-break-if-<=/imm32/next
15544 _Primitive-break-if-<=:  # (payload primitive)
15545     0x11/imm32/alloc-id:fake:payload
15546     0x11/imm32/alloc-id:fake
15547     _string-break-if-<=/imm32/name
15548     0/imm32/no-inouts
15549     0/imm32/no-inouts
15550     0/imm32/no-outputs
15551     0/imm32/no-outputs
15552     0x11/imm32/alloc-id:fake
15553     _string_0f_8e_jump_break/imm32/subx-name
15554     0/imm32/no-rm32
15555     0/imm32/no-r32
15556     0/imm32/no-imm32
15557     0/imm32/no-disp32
15558     0/imm32/no-output
15559     0x11/imm32/alloc-id:fake
15560     _Primitive-break-if->/imm32/next
15561 _Primitive-break-if->:  # (payload primitive)
15562     0x11/imm32/alloc-id:fake:payload
15563     0x11/imm32/alloc-id:fake
15564     _string-break-if->/imm32/name
15565     0/imm32/no-inouts
15566     0/imm32/no-inouts
15567     0/imm32/no-outputs
15568     0/imm32/no-outputs
15569     0x11/imm32/alloc-id:fake
15570     _string_0f_8f_jump_break/imm32/subx-name
15571     0/imm32/no-rm32
15572     0/imm32/no-r32
15573     0/imm32/no-imm32
15574     0/imm32/no-disp32
15575     0/imm32/no-output
15576     0x11/imm32/alloc-id:fake
15577     _Primitive-break/imm32/next
15578 _Primitive-break:  # (payload primitive)
15579     0x11/imm32/alloc-id:fake:payload
15580     0x11/imm32/alloc-id:fake
15581     _string-break/imm32/name
15582     0/imm32/no-inouts
15583     0/imm32/no-inouts
15584     0/imm32/no-outputs
15585     0/imm32/no-outputs
15586     0x11/imm32/alloc-id:fake
15587     _string_e9_jump_break/imm32/subx-name
15588     0/imm32/no-rm32
15589     0/imm32/no-r32
15590     0/imm32/no-imm32
15591     0/imm32/no-disp32
15592     0/imm32/no-output
15593     0x11/imm32/alloc-id:fake
15594     _Primitive-loop-if-addr</imm32/next
15595 _Primitive-loop-if-addr<:  # (payload primitive)
15596     0x11/imm32/alloc-id:fake:payload
15597     0x11/imm32/alloc-id:fake
15598     _string-loop-if-addr</imm32/name
15599     0/imm32/no-inouts
15600     0/imm32/no-inouts
15601     0/imm32/no-outputs
15602     0/imm32/no-outputs
15603     0x11/imm32/alloc-id:fake
15604     _string_0f_82_jump_loop/imm32/subx-name
15605     0/imm32/no-rm32
15606     0/imm32/no-r32
15607     0/imm32/no-imm32
15608     0/imm32/no-disp32
15609     0/imm32/no-output
15610     0x11/imm32/alloc-id:fake
15611     _Primitive-loop-if-addr>=/imm32/next
15612 _Primitive-loop-if-addr>=:  # (payload primitive)
15613     0x11/imm32/alloc-id:fake:payload
15614     0x11/imm32/alloc-id:fake
15615     _string-loop-if-addr>=/imm32/name
15616     0/imm32/no-inouts
15617     0/imm32/no-inouts
15618     0/imm32/no-outputs
15619     0/imm32/no-outputs
15620     0x11/imm32/alloc-id:fake
15621     _string_0f_83_jump_loop/imm32/subx-name
15622     0/imm32/no-rm32
15623     0/imm32/no-r32
15624     0/imm32/no-imm32
15625     0/imm32/no-disp32
15626     0/imm32/no-output
15627     0x11/imm32/alloc-id:fake
15628     _Primitive-loop-if-=/imm32/next
15629 _Primitive-loop-if-=:  # (payload primitive)
15630     0x11/imm32/alloc-id:fake:payload
15631     0x11/imm32/alloc-id:fake
15632     _string-loop-if-=/imm32/name
15633     0/imm32/no-inouts
15634     0/imm32/no-inouts
15635     0/imm32/no-outputs
15636     0/imm32/no-outputs
15637     0x11/imm32/alloc-id:fake
15638     _string_0f_84_jump_loop/imm32/subx-name
15639     0/imm32/no-rm32
15640     0/imm32/no-r32
15641     0/imm32/no-imm32
15642     0/imm32/no-disp32
15643     0/imm32/no-output
15644     0x11/imm32/alloc-id:fake
15645     _Primitive-loop-if-!=/imm32/next
15646 _Primitive-loop-if-!=:  # (payload primitive)
15647     0x11/imm32/alloc-id:fake:payload
15648     0x11/imm32/alloc-id:fake
15649     _string-loop-if-!=/imm32/name
15650     0/imm32/no-inouts
15651     0/imm32/no-inouts
15652     0/imm32/no-outputs
15653     0/imm32/no-outputs
15654     0x11/imm32/alloc-id:fake
15655     _string_0f_85_jump_loop/imm32/subx-name
15656     0/imm32/no-rm32
15657     0/imm32/no-r32
15658     0/imm32/no-imm32
15659     0/imm32/no-disp32
15660     0/imm32/no-output
15661     0x11/imm32/alloc-id:fake
15662     _Primitive-loop-if-addr<=/imm32/next
15663 _Primitive-loop-if-addr<=:  # (payload primitive)
15664     0x11/imm32/alloc-id:fake:payload
15665     0x11/imm32/alloc-id:fake
15666     _string-loop-if-addr<=/imm32/name
15667     0/imm32/no-inouts
15668     0/imm32/no-inouts
15669     0/imm32/no-outputs
15670     0/imm32/no-outputs
15671     0x11/imm32/alloc-id:fake
15672     _string_0f_86_jump_loop/imm32/subx-name
15673     0/imm32/no-rm32
15674     0/imm32/no-r32
15675     0/imm32/no-imm32
15676     0/imm32/no-disp32
15677     0/imm32/no-output
15678     0x11/imm32/alloc-id:fake
15679     _Primitive-loop-if-addr>/imm32/next
15680 _Primitive-loop-if-addr>:  # (payload primitive)
15681     0x11/imm32/alloc-id:fake:payload
15682     0x11/imm32/alloc-id:fake
15683     _string-loop-if-addr>/imm32/name
15684     0/imm32/no-inouts
15685     0/imm32/no-inouts
15686     0/imm32/no-outputs
15687     0/imm32/no-outputs
15688     0x11/imm32/alloc-id:fake
15689     _string_0f_87_jump_loop/imm32/subx-name
15690     0/imm32/no-rm32
15691     0/imm32/no-r32
15692     0/imm32/no-imm32
15693     0/imm32/no-disp32
15694     0/imm32/no-output
15695     0x11/imm32/alloc-id:fake
15696     _Primitive-loop-if-</imm32/next
15697 _Primitive-loop-if-<:  # (payload primitive)
15698     0x11/imm32/alloc-id:fake:payload
15699     0x11/imm32/alloc-id:fake
15700     _string-loop-if-</imm32/name
15701     0/imm32/no-inouts
15702     0/imm32/no-inouts
15703     0/imm32/no-outputs
15704     0/imm32/no-outputs
15705     0x11/imm32/alloc-id:fake
15706     _string_0f_8c_jump_loop/imm32/subx-name
15707     0/imm32/no-rm32
15708     0/imm32/no-r32
15709     0/imm32/no-imm32
15710     0/imm32/no-disp32
15711     0/imm32/no-output
15712     0x11/imm32/alloc-id:fake
15713     _Primitive-loop-if->=/imm32/next
15714 _Primitive-loop-if->=:  # (payload primitive)
15715     0x11/imm32/alloc-id:fake:payload
15716     0x11/imm32/alloc-id:fake
15717     _string-loop-if->=/imm32/name
15718     0/imm32/no-inouts
15719     0/imm32/no-inouts
15720     0/imm32/no-outputs
15721     0/imm32/no-outputs
15722     0x11/imm32/alloc-id:fake
15723     _string_0f_8d_jump_loop/imm32/subx-name
15724     0/imm32/no-rm32
15725     0/imm32/no-r32
15726     0/imm32/no-imm32
15727     0/imm32/no-disp32
15728     0/imm32/no-output
15729     0x11/imm32/alloc-id:fake
15730     _Primitive-loop-if-<=/imm32/next
15731 _Primitive-loop-if-<=:  # (payload primitive)
15732     0x11/imm32/alloc-id:fake:payload
15733     0x11/imm32/alloc-id:fake
15734     _string-loop-if-<=/imm32/name
15735     0/imm32/no-inouts
15736     0/imm32/no-inouts
15737     0/imm32/no-outputs
15738     0/imm32/no-outputs
15739     0x11/imm32/alloc-id:fake
15740     _string_0f_8e_jump_loop/imm32/subx-name
15741     0/imm32/no-rm32
15742     0/imm32/no-r32
15743     0/imm32/no-imm32
15744     0/imm32/no-disp32
15745     0/imm32/no-output
15746     0x11/imm32/alloc-id:fake
15747     _Primitive-loop-if->/imm32/next
15748 _Primitive-loop-if->:  # (payload primitive)
15749     0x11/imm32/alloc-id:fake:payload
15750     0x11/imm32/alloc-id:fake
15751     _string-loop-if->/imm32/name
15752     0/imm32/no-inouts
15753     0/imm32/no-inouts
15754     0/imm32/no-outputs
15755     0/imm32/no-outputs
15756     0x11/imm32/alloc-id:fake
15757     _string_0f_8f_jump_loop/imm32/subx-name
15758     0/imm32/no-rm32
15759     0/imm32/no-r32
15760     0/imm32/no-imm32
15761     0/imm32/no-disp32
15762     0/imm32/no-output
15763     0x11/imm32/alloc-id:fake
15764     _Primitive-loop/imm32/next  # we probably don't need an unconditional break
15765 _Primitive-loop:  # (payload primitive)
15766     0x11/imm32/alloc-id:fake:payload
15767     0x11/imm32/alloc-id:fake
15768     _string-loop/imm32/name
15769     0/imm32/no-inouts
15770     0/imm32/no-inouts
15771     0/imm32/no-outputs
15772     0/imm32/no-outputs
15773     0x11/imm32/alloc-id:fake
15774     _string_e9_jump_loop/imm32/subx-name
15775     0/imm32/no-rm32
15776     0/imm32/no-r32
15777     0/imm32/no-imm32
15778     0/imm32/no-disp32
15779     0/imm32/no-output
15780     0x11/imm32/alloc-id:fake
15781     _Primitive-break-if-addr<-named/imm32/next
15782 # - branches to named blocks
15783 _Primitive-break-if-addr<-named:  # (payload primitive)
15784     0x11/imm32/alloc-id:fake:payload
15785     0x11/imm32/alloc-id:fake
15786     _string-break-if-addr</imm32/name
15787     0x11/imm32/alloc-id:fake
15788     Single-lit-var/imm32/inouts
15789     0/imm32/no-outputs
15790     0/imm32/no-outputs
15791     0x11/imm32/alloc-id:fake
15792     _string_0f_82_jump_label/imm32/subx-name
15793     0/imm32/no-rm32
15794     0/imm32/no-r32
15795     0/imm32/no-imm32
15796     1/imm32/disp32-is-first-inout
15797     0/imm32/no-output
15798     0x11/imm32/alloc-id:fake
15799     _Primitive-break-if-addr>=-named/imm32/next
15800 _Primitive-break-if-addr>=-named:  # (payload primitive)
15801     0x11/imm32/alloc-id:fake:payload
15802     0x11/imm32/alloc-id:fake
15803     _string-break-if-addr>=/imm32/name
15804     0x11/imm32/alloc-id:fake
15805     Single-lit-var/imm32/inouts
15806     0/imm32/no-outputs
15807     0/imm32/no-outputs
15808     0x11/imm32/alloc-id:fake
15809     _string_0f_83_jump_label/imm32/subx-name
15810     0/imm32/no-rm32
15811     0/imm32/no-r32
15812     0/imm32/no-imm32
15813     1/imm32/disp32-is-first-inout
15814     0/imm32/no-output
15815     0x11/imm32/alloc-id:fake
15816     _Primitive-break-if-=-named/imm32/next
15817 _Primitive-break-if-=-named:  # (payload primitive)
15818     0x11/imm32/alloc-id:fake:payload
15819     0x11/imm32/alloc-id:fake
15820     _string-break-if-=/imm32/name
15821     0x11/imm32/alloc-id:fake
15822     Single-lit-var/imm32/inouts
15823     0/imm32/no-outputs
15824     0/imm32/no-outputs
15825     0x11/imm32/alloc-id:fake
15826     _string_0f_84_jump_label/imm32/subx-name
15827     0/imm32/no-rm32
15828     0/imm32/no-r32
15829     0/imm32/no-imm32
15830     1/imm32/disp32-is-first-inout
15831     0/imm32/no-output
15832     0x11/imm32/alloc-id:fake
15833     _Primitive-break-if-!=-named/imm32/next
15834 _Primitive-break-if-!=-named:  # (payload primitive)
15835     0x11/imm32/alloc-id:fake:payload
15836     0x11/imm32/alloc-id:fake
15837     _string-break-if-!=/imm32/name
15838     0x11/imm32/alloc-id:fake
15839     Single-lit-var/imm32/inouts
15840     0/imm32/no-outputs
15841     0/imm32/no-outputs
15842     0x11/imm32/alloc-id:fake
15843     _string_0f_85_jump_label/imm32/subx-name
15844     0/imm32/no-rm32
15845     0/imm32/no-r32
15846     0/imm32/no-imm32
15847     1/imm32/disp32-is-first-inout
15848     0/imm32/no-output
15849     0x11/imm32/alloc-id:fake
15850     _Primitive-break-if-addr<=-named/imm32/next
15851 _Primitive-break-if-addr<=-named:  # (payload primitive)
15852     0x11/imm32/alloc-id:fake:payload
15853     0x11/imm32/alloc-id:fake
15854     _string-break-if-addr<=/imm32/name
15855     0x11/imm32/alloc-id:fake
15856     Single-lit-var/imm32/inouts
15857     0/imm32/no-outputs
15858     0/imm32/no-outputs
15859     0x11/imm32/alloc-id:fake
15860     _string_0f_86_jump_label/imm32/subx-name
15861     0/imm32/no-rm32
15862     0/imm32/no-r32
15863     0/imm32/no-imm32
15864     1/imm32/disp32-is-first-inout
15865     0/imm32/no-output
15866     0x11/imm32/alloc-id:fake
15867     _Primitive-break-if-addr>-named/imm32/next
15868 _Primitive-break-if-addr>-named:  # (payload primitive)
15869     0x11/imm32/alloc-id:fake:payload
15870     0x11/imm32/alloc-id:fake
15871     _string-break-if-addr>/imm32/name
15872     0x11/imm32/alloc-id:fake
15873     Single-lit-var/imm32/inouts
15874     0/imm32/no-outputs
15875     0/imm32/no-outputs
15876     0x11/imm32/alloc-id:fake
15877     _string_0f_87_jump_label/imm32/subx-name
15878     0/imm32/no-rm32
15879     0/imm32/no-r32
15880     0/imm32/no-imm32
15881     1/imm32/disp32-is-first-inout
15882     0/imm32/no-output
15883     0x11/imm32/alloc-id:fake
15884     _Primitive-break-if-<-named/imm32/next
15885 _Primitive-break-if-<-named:  # (payload primitive)
15886     0x11/imm32/alloc-id:fake:payload
15887     0x11/imm32/alloc-id:fake
15888     _string-break-if-</imm32/name
15889     0x11/imm32/alloc-id:fake
15890     Single-lit-var/imm32/inouts
15891     0/imm32/no-outputs
15892     0/imm32/no-outputs
15893     0x11/imm32/alloc-id:fake
15894     _string_0f_8c_jump_label/imm32/subx-name
15895     0/imm32/no-rm32
15896     0/imm32/no-r32
15897     0/imm32/no-imm32
15898     1/imm32/disp32-is-first-inout
15899     0/imm32/no-output
15900     0x11/imm32/alloc-id:fake
15901     _Primitive-break-if->=-named/imm32/next
15902 _Primitive-break-if->=-named:  # (payload primitive)
15903     0x11/imm32/alloc-id:fake:payload
15904     0x11/imm32/alloc-id:fake
15905     _string-break-if->=/imm32/name
15906     0x11/imm32/alloc-id:fake
15907     Single-lit-var/imm32/inouts
15908     0/imm32/no-outputs
15909     0/imm32/no-outputs
15910     0x11/imm32/alloc-id:fake
15911     _string_0f_8d_jump_label/imm32/subx-name
15912     0/imm32/no-rm32
15913     0/imm32/no-r32
15914     0/imm32/no-imm32
15915     1/imm32/disp32-is-first-inout
15916     0/imm32/no-output
15917     0x11/imm32/alloc-id:fake
15918     _Primitive-break-if-<=-named/imm32/next
15919 _Primitive-break-if-<=-named:  # (payload primitive)
15920     0x11/imm32/alloc-id:fake:payload
15921     0x11/imm32/alloc-id:fake
15922     _string-break-if-<=/imm32/name
15923     0x11/imm32/alloc-id:fake
15924     Single-lit-var/imm32/inouts
15925     0/imm32/no-outputs
15926     0/imm32/no-outputs
15927     0x11/imm32/alloc-id:fake
15928     _string_0f_8e_jump_label/imm32/subx-name
15929     0/imm32/no-rm32
15930     0/imm32/no-r32
15931     0/imm32/no-imm32
15932     1/imm32/disp32-is-first-inout
15933     0/imm32/no-output
15934     0x11/imm32/alloc-id:fake
15935     _Primitive-break-if->-named/imm32/next
15936 _Primitive-break-if->-named:  # (payload primitive)
15937     0x11/imm32/alloc-id:fake:payload
15938     0x11/imm32/alloc-id:fake
15939     _string-break-if->/imm32/name
15940     0x11/imm32/alloc-id:fake
15941     Single-lit-var/imm32/inouts
15942     0/imm32/no-outputs
15943     0/imm32/no-outputs
15944     0x11/imm32/alloc-id:fake
15945     _string_0f_8f_jump_label/imm32/subx-name
15946     0/imm32/no-rm32
15947     0/imm32/no-r32
15948     0/imm32/no-imm32
15949     1/imm32/disp32-is-first-inout
15950     0/imm32/no-output
15951     0x11/imm32/alloc-id:fake
15952     _Primitive-break-named/imm32/next
15953 _Primitive-break-named:  # (payload primitive)
15954     0x11/imm32/alloc-id:fake:payload
15955     0x11/imm32/alloc-id:fake
15956     _string-break/imm32/name
15957     0x11/imm32/alloc-id:fake
15958     Single-lit-var/imm32/inouts
15959     0/imm32/no-outputs
15960     0/imm32/no-outputs
15961     0x11/imm32/alloc-id:fake
15962     _string_e9_jump_label/imm32/subx-name
15963     0/imm32/no-rm32
15964     0/imm32/no-r32
15965     0/imm32/no-imm32
15966     1/imm32/disp32-is-first-inout
15967     0/imm32/no-output
15968     0x11/imm32/alloc-id:fake
15969     _Primitive-loop-if-addr<-named/imm32/next
15970 _Primitive-loop-if-addr<-named:  # (payload primitive)
15971     0x11/imm32/alloc-id:fake:payload
15972     0x11/imm32/alloc-id:fake
15973     _string-loop-if-addr</imm32/name
15974     0x11/imm32/alloc-id:fake
15975     Single-lit-var/imm32/inouts
15976     0/imm32/no-outputs
15977     0/imm32/no-outputs
15978     0x11/imm32/alloc-id:fake
15979     _string_0f_82_jump_label/imm32/subx-name
15980     0/imm32/no-rm32
15981     0/imm32/no-r32
15982     0/imm32/no-imm32
15983     1/imm32/disp32-is-first-inout
15984     0/imm32/no-output
15985     0x11/imm32/alloc-id:fake
15986     _Primitive-loop-if-addr>=-named/imm32/next
15987 _Primitive-loop-if-addr>=-named:  # (payload primitive)
15988     0x11/imm32/alloc-id:fake:payload
15989     0x11/imm32/alloc-id:fake
15990     _string-loop-if-addr>=/imm32/name
15991     0x11/imm32/alloc-id:fake
15992     Single-lit-var/imm32/inouts
15993     0/imm32/no-outputs
15994     0/imm32/no-outputs
15995     0x11/imm32/alloc-id:fake
15996     _string_0f_83_jump_label/imm32/subx-name
15997     0/imm32/no-rm32
15998     0/imm32/no-r32
15999     0/imm32/no-imm32
16000     1/imm32/disp32-is-first-inout
16001     0/imm32/no-output
16002     0x11/imm32/alloc-id:fake
16003     _Primitive-loop-if-=-named/imm32/next
16004 _Primitive-loop-if-=-named:  # (payload primitive)
16005     0x11/imm32/alloc-id:fake:payload
16006     0x11/imm32/alloc-id:fake
16007     _string-loop-if-=/imm32/name
16008     0x11/imm32/alloc-id:fake
16009     Single-lit-var/imm32/inouts
16010     0/imm32/no-outputs
16011     0/imm32/no-outputs
16012     0x11/imm32/alloc-id:fake
16013     _string_0f_84_jump_label/imm32/subx-name
16014     0/imm32/no-rm32
16015     0/imm32/no-r32
16016     0/imm32/no-imm32
16017     1/imm32/disp32-is-first-inout
16018     0/imm32/no-output
16019     0x11/imm32/alloc-id:fake
16020     _Primitive-loop-if-!=-named/imm32/next
16021 _Primitive-loop-if-!=-named:  # (payload primitive)
16022     0x11/imm32/alloc-id:fake:payload
16023     0x11/imm32/alloc-id:fake
16024     _string-loop-if-!=/imm32/name
16025     0x11/imm32/alloc-id:fake
16026     Single-lit-var/imm32/inouts
16027     0/imm32/no-outputs
16028     0/imm32/no-outputs
16029     0x11/imm32/alloc-id:fake
16030     _string_0f_85_jump_label/imm32/subx-name
16031     0/imm32/no-rm32
16032     0/imm32/no-r32
16033     0/imm32/no-imm32
16034     1/imm32/disp32-is-first-inout
16035     0/imm32/no-output
16036     0x11/imm32/alloc-id:fake
16037     _Primitive-loop-if-addr<=-named/imm32/next
16038 _Primitive-loop-if-addr<=-named:  # (payload primitive)
16039     0x11/imm32/alloc-id:fake:payload
16040     0x11/imm32/alloc-id:fake
16041     _string-loop-if-addr<=/imm32/name
16042     0x11/imm32/alloc-id:fake
16043     Single-lit-var/imm32/inouts
16044     0/imm32/no-outputs
16045     0/imm32/no-outputs
16046     0x11/imm32/alloc-id:fake
16047     _string_0f_86_jump_label/imm32/subx-name
16048     0/imm32/no-rm32
16049     0/imm32/no-r32
16050     0/imm32/no-imm32
16051     1/imm32/disp32-is-first-inout
16052     0/imm32/no-output
16053     0x11/imm32/alloc-id:fake
16054     _Primitive-loop-if-addr>-named/imm32/next
16055 _Primitive-loop-if-addr>-named:  # (payload primitive)
16056     0x11/imm32/alloc-id:fake:payload
16057     0x11/imm32/alloc-id:fake
16058     _string-loop-if-addr>/imm32/name
16059     0x11/imm32/alloc-id:fake
16060     Single-lit-var/imm32/inouts
16061     0/imm32/no-outputs
16062     0/imm32/no-outputs
16063     0x11/imm32/alloc-id:fake
16064     _string_0f_87_jump_label/imm32/subx-name
16065     0/imm32/no-rm32
16066     0/imm32/no-r32
16067     0/imm32/no-imm32
16068     1/imm32/disp32-is-first-inout
16069     0/imm32/no-output
16070     0x11/imm32/alloc-id:fake
16071     _Primitive-loop-if-<-named/imm32/next
16072 _Primitive-loop-if-<-named:  # (payload primitive)
16073     0x11/imm32/alloc-id:fake:payload
16074     0x11/imm32/alloc-id:fake
16075     _string-loop-if-</imm32/name
16076     0x11/imm32/alloc-id:fake
16077     Single-lit-var/imm32/inouts
16078     0/imm32/no-outputs
16079     0/imm32/no-outputs
16080     0x11/imm32/alloc-id:fake
16081     _string_0f_8c_jump_label/imm32/subx-name
16082     0/imm32/no-rm32
16083     0/imm32/no-r32
16084     0/imm32/no-imm32
16085     1/imm32/disp32-is-first-inout
16086     0/imm32/no-output
16087     0x11/imm32/alloc-id:fake
16088     _Primitive-loop-if->=-named/imm32/next
16089 _Primitive-loop-if->=-named:  # (payload primitive)
16090     0x11/imm32/alloc-id:fake:payload
16091     0x11/imm32/alloc-id:fake
16092     _string-loop-if->=/imm32/name
16093     0x11/imm32/alloc-id:fake
16094     Single-lit-var/imm32/inouts
16095     0/imm32/no-outputs
16096     0/imm32/no-outputs
16097     0x11/imm32/alloc-id:fake
16098     _string_0f_8d_jump_label/imm32/subx-name
16099     0/imm32/no-rm32
16100     0/imm32/no-r32
16101     0/imm32/no-imm32
16102     1/imm32/disp32-is-first-inout
16103     0/imm32/no-output
16104     0x11/imm32/alloc-id:fake
16105     _Primitive-loop-if-<=-named/imm32/next
16106 _Primitive-loop-if-<=-named:  # (payload primitive)
16107     0x11/imm32/alloc-id:fake:payload
16108     0x11/imm32/alloc-id:fake
16109     _string-loop-if-<=/imm32/name
16110     0x11/imm32/alloc-id:fake
16111     Single-lit-var/imm32/inouts
16112     0/imm32/no-outputs
16113     0/imm32/no-outputs
16114     0x11/imm32/alloc-id:fake
16115     _string_0f_8e_jump_label/imm32/subx-name
16116     0/imm32/no-rm32
16117     0/imm32/no-r32
16118     0/imm32/no-imm32
16119     1/imm32/disp32-is-first-inout
16120     0/imm32/no-output
16121     0x11/imm32/alloc-id:fake
16122     _Primitive-loop-if->-named/imm32/next
16123 _Primitive-loop-if->-named:  # (payload primitive)
16124     0x11/imm32/alloc-id:fake:payload
16125     0x11/imm32/alloc-id:fake
16126     _string-loop-if->/imm32/name
16127     0x11/imm32/alloc-id:fake
16128     Single-lit-var/imm32/inouts
16129     0/imm32/no-outputs
16130     0/imm32/no-outputs
16131     0x11/imm32/alloc-id:fake
16132     _string_0f_8f_jump_label/imm32/subx-name
16133     0/imm32/no-rm32
16134     0/imm32/no-r32
16135     0/imm32/no-imm32
16136     1/imm32/disp32-is-first-inout
16137     0/imm32/no-output
16138     0x11/imm32/alloc-id:fake
16139     _Primitive-loop-named/imm32/next  # we probably don't need an unconditional break
16140 _Primitive-loop-named:  # (payload primitive)
16141     0x11/imm32/alloc-id:fake:payload
16142     0x11/imm32/alloc-id:fake
16143     _string-loop/imm32/name
16144     0x11/imm32/alloc-id:fake
16145     Single-lit-var/imm32/inouts
16146     0/imm32/no-outputs
16147     0/imm32/no-outputs
16148     0x11/imm32/alloc-id:fake
16149     _string_e9_jump_label/imm32/subx-name
16150     0/imm32/no-rm32
16151     0/imm32/no-r32
16152     0/imm32/no-imm32
16153     1/imm32/disp32-is-first-inout
16154     0/imm32/no-output
16155     0/imm32/next
16156     0/imm32/next
16157 
16158 # string literals for Mu instructions
16159 _string-add:  # (payload array byte)
16160     0x11/imm32/alloc-id:fake:payload
16161     # "add"
16162     0x3/imm32/size
16163     0x61/a 0x64/d 0x64/d
16164 _string-address:  # (payload array byte)
16165     0x11/imm32/alloc-id:fake:payload
16166     # "address"
16167     0x7/imm32/size
16168     0x61/a 0x64/d 0x64/d 0x72/r 0x65/e 0x73/s 0x73/s
16169 _string-add-to:  # (payload array byte)
16170     0x11/imm32/alloc-id:fake:payload
16171     # "add-to"
16172     0x6/imm32/size
16173     0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
16174 _string-and:  # (payload array byte)
16175     0x11/imm32/alloc-id:fake:payload
16176     # "and"
16177     0x3/imm32/size
16178     0x61/a 0x6e/n 0x64/d
16179 _string-and-with:  # (payload array byte)
16180     0x11/imm32/alloc-id:fake:payload
16181     # "and-with"
16182     0x8/imm32/size
16183     0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
16184 _string-break:  # (payload array byte)
16185     0x11/imm32/alloc-id:fake:payload
16186     # "break"
16187     0x5/imm32/size
16188     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k
16189 _string-break-if-<:  # (payload array byte)
16190     0x11/imm32/alloc-id:fake:payload
16191     # "break-if-<"
16192     0xa/imm32/size
16193     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
16194 _string-break-if-<=:  # (payload array byte)
16195     0x11/imm32/alloc-id:fake:payload
16196     # "break-if-<="
16197     0xb/imm32/size
16198     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
16199 _string-break-if-=:  # (payload array byte)
16200     0x11/imm32/alloc-id:fake:payload
16201     # "break-if-="
16202     0xa/imm32/size
16203     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
16204 _string-break-if->:  # (payload array byte)
16205     0x11/imm32/alloc-id:fake:payload
16206     # "break-if->"
16207     0xa/imm32/size
16208     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
16209 _string-break-if->=:  # (payload array byte)
16210     0x11/imm32/alloc-id:fake:payload
16211     # "break-if->="
16212     0xb/imm32/size
16213     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
16214 _string-break-if-!=:  # (payload array byte)
16215     0x11/imm32/alloc-id:fake:payload
16216     # "break-if-!="
16217     0xb/imm32/size
16218     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
16219 _string-break-if-addr<:  # (payload array byte)
16220     0x11/imm32/alloc-id:fake:payload
16221     # "break-if-addr<"
16222     0xe/imm32/size
16223     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/<
16224 _string-break-if-addr<=:  # (payload array byte)
16225     0x11/imm32/alloc-id:fake:payload
16226     # "break-if-addr<="
16227     0xf/imm32/size
16228     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/=
16229 _string-break-if-addr>:  # (payload array byte)
16230     0x11/imm32/alloc-id:fake:payload
16231     # "break-if-addr>"
16232     0xe/imm32/size
16233     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/>
16234 _string-break-if-addr>=:  # (payload array byte)
16235     0x11/imm32/alloc-id:fake:payload
16236     # "break-if-addr>="
16237     0xf/imm32/size
16238     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/=
16239 _string-compare:  # (payload array byte)
16240     0x11/imm32/alloc-id:fake:payload
16241     # "compare"
16242     0x7/imm32/size
16243     0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e
16244 _string-copy:  # (payload array byte)
16245     0x11/imm32/alloc-id:fake:payload
16246     # "copy"
16247     0x4/imm32/size
16248     0x63/c 0x6f/o 0x70/p 0x79/y
16249 _string-copy-to:  # (payload array byte)
16250     0x11/imm32/alloc-id:fake:payload
16251     # "copy-to"
16252     0x7/imm32/size
16253     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o
16254 _string-copy-byte:
16255     0x11/imm32/alloc-id:fake:payload
16256     # "copy-byte"
16257     0x9/imm32/size
16258     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e
16259 _string-copy-byte-to:
16260     0x11/imm32/alloc-id:fake:payload
16261     # "copy-byte-to"
16262     0xc/imm32/size
16263     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x74/t 0x6f/o
16264 _string-decrement:  # (payload array byte)
16265     0x11/imm32/alloc-id:fake:payload
16266     # "decrement"
16267     0x9/imm32/size
16268     0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
16269 _string-increment:  # (payload array byte)
16270     0x11/imm32/alloc-id:fake:payload
16271     # "increment"
16272     0x9/imm32/size
16273     0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
16274 _string-loop:  # (payload array byte)
16275     0x11/imm32/alloc-id:fake:payload
16276     # "loop"
16277     0x4/imm32/size
16278     0x6c/l 0x6f/o 0x6f/o 0x70/p
16279 _string-loop-if-<:  # (payload array byte)
16280     0x11/imm32/alloc-id:fake:payload
16281     # "loop-if-<"
16282     0x9/imm32/size
16283     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
16284 _string-loop-if-<=:  # (payload array byte)
16285     0x11/imm32/alloc-id:fake:payload
16286     # "loop-if-<="
16287     0xa/imm32/size
16288     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
16289 _string-loop-if-=:  # (payload array byte)
16290     0x11/imm32/alloc-id:fake:payload
16291     # "loop-if-="
16292     0x9/imm32/size
16293     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
16294 _string-loop-if->:  # (payload array byte)
16295     0x11/imm32/alloc-id:fake:payload
16296     # "loop-if->"
16297     0x9/imm32/size
16298     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
16299 _string-loop-if->=:  # (payload array byte)
16300     0x11/imm32/alloc-id:fake:payload
16301     # "loop-if->="
16302     0xa/imm32/size
16303     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
16304 _string-loop-if-!=:  # (payload array byte)
16305     0x11/imm32/alloc-id:fake:payload
16306     # "loop-if-!="
16307     0xa/imm32/size
16308     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
16309 _string-loop-if-addr<:  # (payload array byte)
16310     0x11/imm32/alloc-id:fake:payload
16311     # "loop-if-addr<"
16312     0xd/imm32/size
16313     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/<
16314 _string-loop-if-addr<=:  # (payload array byte)
16315     0x11/imm32/alloc-id:fake:payload
16316     # "loop-if-addr<="
16317     0xe/imm32/size
16318     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/=
16319 _string-loop-if-addr>:  # (payload array byte)
16320     0x11/imm32/alloc-id:fake:payload
16321     # "loop-if-addr>"
16322     0xd/imm32/size
16323     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/>
16324 _string-loop-if-addr>=:  # (payload array byte)
16325     0x11/imm32/alloc-id:fake:payload
16326     # "loop-if-addr>="
16327     0xe/imm32/size
16328     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/=
16329 _string-multiply:  # (payload array byte)
16330     0x11/imm32/alloc-id:fake:payload
16331     # "multiply"
16332     0x8/imm32/size
16333     0x6d/m 0x75/u 0x6c/l 0x74/t 0x69/i 0x70/p 0x6c/l 0x79/y
16334 _string-or:  # (payload array byte)
16335     0x11/imm32/alloc-id:fake:payload
16336     # "or"
16337     0x2/imm32/size
16338     0x6f/o 0x72/r
16339 _string-or-with:  # (payload array byte)
16340     0x11/imm32/alloc-id:fake:payload
16341     # "or-with"
16342     0x7/imm32/size
16343     0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
16344 _string-subtract:  # (payload array byte)
16345     0x11/imm32/alloc-id:fake:payload
16346     # "subtract"
16347     0x8/imm32/size
16348     0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
16349 _string-subtract-from:  # (payload array byte)
16350     0x11/imm32/alloc-id:fake:payload
16351     # "subtract-from"
16352     0xd/imm32/size
16353     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
16354 _string-xor:  # (payload array byte)
16355     0x11/imm32/alloc-id:fake:payload
16356     # "xor"
16357     0x3/imm32/size
16358     0x78/x 0x6f/o 0x72/r
16359 _string-xor-with:  # (payload array byte)
16360     0x11/imm32/alloc-id:fake:payload
16361     # "xor-with"
16362     0x8/imm32/size
16363     0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
16364 
16365 # string literals for SubX instructions
16366 _string_01_add_to:  # (payload array byte)
16367     0x11/imm32/alloc-id:fake:payload
16368     # "01/add-to"
16369     0x9/imm32/size
16370     0x30/0 0x31/1 0x2f/slash 0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
16371 _string_03_add:  # (payload array byte)
16372     0x11/imm32/alloc-id:fake:payload
16373     # "03/add"
16374     0x6/imm32/size
16375     0x30/0 0x33/3 0x2f/slash 0x61/a 0x64/d 0x64/d
16376 _string_05_add_to_eax:  # (payload array byte)
16377     0x11/imm32/alloc-id:fake:payload
16378     # "05/add-to-eax"
16379     0xd/imm32/size
16380     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
16381 _string_09_or_with:  # (payload array byte)
16382     0x11/imm32/alloc-id:fake:payload
16383     # "09/or-with"
16384     0xa/imm32/size
16385     0x30/0 0x39/9 0x2f/slash 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
16386 _string_0b_or:  # (payload array byte)
16387     0x11/imm32/alloc-id:fake:payload
16388     # "0b/or"
16389     0x5/imm32/size
16390     0x30/0 0x62/b 0x2f/slash 0x6f/o 0x72/r
16391 _string_0d_or_with_eax:  # (payload array byte)
16392     0x11/imm32/alloc-id:fake:payload
16393     # "0d/or-with-eax"
16394     0xe/imm32/size
16395     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
16396 _string_0f_82_jump_label:  # (payload array byte)
16397     0x11/imm32/alloc-id:fake:payload
16398     # "0f 82/jump-if-addr<"
16399     0x13/imm32/size
16400     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/<
16401 _string_0f_82_jump_break:  # (payload array byte)
16402     0x11/imm32/alloc-id:fake:payload
16403     # "0f 82/jump-if-addr< break/disp32"
16404     0x20/imm32/size
16405     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
16406 _string_0f_82_jump_loop:  # (payload array byte)
16407     0x11/imm32/alloc-id:fake:payload
16408     # "0f 82/jump-if-addr< loop/disp32"
16409     0x1f/imm32/size
16410     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
16411 _string_0f_83_jump_label:  # (payload array byte)
16412     0x11/imm32/alloc-id:fake:payload
16413     # "0f 83/jump-if-addr>="
16414     0x14/imm32/size
16415     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/=
16416 _string_0f_83_jump_break:  # (payload array byte)
16417     0x11/imm32/alloc-id:fake:payload
16418     # "0f 83/jump-if-addr>= break/disp32"
16419     0x21/imm32/size
16420     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
16421 _string_0f_83_jump_loop:  # (payload array byte)
16422     0x11/imm32/alloc-id:fake:payload
16423     # "0f 83/jump-if-addr>= loop/disp32"
16424     0x20/imm32/size
16425     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
16426 _string_0f_84_jump_label:  # (payload array byte)
16427     0x11/imm32/alloc-id:fake:payload
16428     # "0f 84/jump-if-="
16429     0xf/imm32/size
16430     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/=
16431 _string_0f_84_jump_break:  # (payload array byte)
16432     0x11/imm32/alloc-id:fake:payload
16433     # "0f 84/jump-if-= break/disp32"
16434     0x1c/imm32/size
16435     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
16436 _string_0f_84_jump_loop:  # (payload array byte)
16437     0x11/imm32/alloc-id:fake:payload
16438     # "0f 84/jump-if-= loop/disp32"
16439     0x1b/imm32/size
16440     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
16441 _string_0f_85_jump_label:  # (payload array byte)
16442     0x11/imm32/alloc-id:fake:payload
16443     # "0f 85/jump-if-!="
16444     0x10/imm32/size
16445     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/=
16446 _string_0f_85_jump_break:  # (payload array byte)
16447     0x11/imm32/alloc-id:fake:payload
16448     # "0f 85/jump-if-!= break/disp32"
16449     0x1d/imm32/size
16450     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
16451 _string_0f_85_jump_loop:  # (payload array byte)
16452     0x11/imm32/alloc-id:fake:payload
16453     # "0f 85/jump-if-!= loop/disp32"
16454     0x1c/imm32/size
16455     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
16456 _string_0f_86_jump_label:  # (payload array byte)
16457     0x11/imm32/alloc-id:fake:payload
16458     # "0f 86/jump-if-addr<="
16459     0x14/imm32/size
16460     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/=
16461 _string_0f_86_jump_break:  # (payload array byte)
16462     0x11/imm32/alloc-id:fake:payload
16463     # "0f 86/jump-if-addr<= break/disp32"
16464     0x21/imm32/size
16465     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
16466 _string_0f_86_jump_loop:  # (payload array byte)
16467     0x11/imm32/alloc-id:fake:payload
16468     # "0f 86/jump-if-addr<= loop/disp32"
16469     0x20/imm32/size
16470     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
16471 _string_0f_87_jump_label:  # (payload array byte)
16472     0x11/imm32/alloc-id:fake:payload
16473     # "0f 87/jump-if-addr>"
16474     0x13/imm32/size
16475     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/>
16476 _string_0f_87_jump_break:  # (payload array byte)
16477     0x11/imm32/alloc-id:fake:payload
16478     # "0f 87/jump-if-addr> break/disp32"
16479     0x20/imm32/size
16480     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
16481 _string_0f_87_jump_loop:  # (payload array byte)
16482     0x11/imm32/alloc-id:fake:payload
16483     # "0f 87/jump-if-addr> loop/disp32"
16484     0x1f/imm32/size
16485     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
16486 _string_0f_8c_jump_label:  # (payload array byte)
16487     0x11/imm32/alloc-id:fake:payload
16488     # "0f 8c/jump-if-<"
16489     0xf/imm32/size
16490     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/<
16491 _string_0f_8c_jump_break:  # (payload array byte)
16492     0x11/imm32/alloc-id:fake:payload
16493     # "0f 8c/jump-if-< break/disp32"
16494     0x1c/imm32/size
16495     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
16496 _string_0f_8c_jump_loop:  # (payload array byte)
16497     0x11/imm32/alloc-id:fake:payload
16498     # "0f 8c/jump-if-< loop/disp32"
16499     0x1b/imm32/size
16500     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
16501 _string_0f_8d_jump_label:  # (payload array byte)
16502     0x11/imm32/alloc-id:fake:payload
16503     # "0f 8d/jump-if->="
16504     0x10/imm32/size
16505     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/=
16506 _string_0f_8d_jump_break:  # (payload array byte)
16507     0x11/imm32/alloc-id:fake:payload
16508     # "0f 8d/jump-if->= break/disp32"
16509     0x1d/imm32/size
16510     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
16511 _string_0f_8d_jump_loop:  # (payload array byte)
16512     0x11/imm32/alloc-id:fake:payload
16513     # "0f 8d/jump-if->= loop/disp32"
16514     0x1c/imm32/size
16515     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
16516 _string_0f_8e_jump_label:  # (payload array byte)
16517     0x11/imm32/alloc-id:fake:payload
16518     # "0f 8e/jump-if-<="
16519     0x10/imm32/size
16520     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/=
16521 _string_0f_8e_jump_break:  # (payload array byte)
16522     0x11/imm32/alloc-id:fake:payload
16523     # "0f 8e/jump-if-<= break/disp32"
16524     0x1d/imm32/size
16525     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
16526 _string_0f_8e_jump_loop:  # (payload array byte)
16527     0x11/imm32/alloc-id:fake:payload
16528     # "0f 8e/jump-if-<= loop/disp32"
16529     0x1c/imm32/size
16530     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
16531 _string_0f_8f_jump_label:  # (payload array byte)
16532     0x11/imm32/alloc-id:fake:payload
16533     # "0f 8f/jump-if->"
16534     0xf/imm32/size
16535     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/>
16536 _string_0f_8f_jump_break:  # (payload array byte)
16537     0x11/imm32/alloc-id:fake:payload
16538     # "0f 8f/jump-if-> break/disp32"
16539     0x1c/imm32/size
16540     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
16541 _string_0f_8f_jump_loop:  # (payload array byte)
16542     0x11/imm32/alloc-id:fake:payload
16543     # "0f 8f/jump-if-> loop/disp32"
16544     0x1b/imm32/size
16545     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
16546 _string_0f_af_multiply:  # (payload array byte)
16547     0x11/imm32/alloc-id:fake:payload
16548     # "0f af/multiply"
16549     0xe/imm32/size
16550     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
16551 _string_21_and_with:  # (payload array byte)
16552     0x11/imm32/alloc-id:fake:payload
16553     # "21/and-with"
16554     0xb/imm32/size
16555     0x32/2 0x31/1 0x2f/slash 0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
16556 _string_23_and:  # (payload array byte)
16557     0x11/imm32/alloc-id:fake:payload
16558     # "23/and"
16559     0x6/imm32/size
16560     0x32/2 0x33/3 0x2f/slash 0x61/a 0x6e/n 0x64/d
16561 _string_25_and_with_eax:  # (payload array byte)
16562     0x11/imm32/alloc-id:fake:payload
16563     # "25/and-with-eax"
16564     0xf/imm32/size
16565     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
16566 _string_29_subtract_from:  # (payload array byte)
16567     0x11/imm32/alloc-id:fake:payload
16568     # "29/subtract-from"
16569     0x10/imm32/size
16570     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
16571 _string_2b_subtract:  # (payload array byte)
16572     0x11/imm32/alloc-id:fake:payload
16573     # "2b/subtract"
16574     0xb/imm32/size
16575     0x32/2 0x62/b 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
16576 _string_2d_subtract_from_eax:  # (payload array byte)
16577     0x11/imm32/alloc-id:fake:payload
16578     # "2d/subtract-from-eax"
16579     0x14/imm32/size
16580     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
16581 _string_31_xor_with:  # (payload array byte)
16582     0x11/imm32/alloc-id:fake:payload
16583     # "31/xor-with"
16584     0xb/imm32/size
16585     0x33/3 0x31/1 0x2f/slash 0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
16586 _string_33_xor:  # (payload array byte)
16587     0x11/imm32/alloc-id:fake:payload
16588     # "33/xor"
16589     0x6/imm32/size
16590     0x33/3 0x33/3 0x2f/slash 0x78/x 0x6f/o 0x72/r
16591 _string_35_xor_with_eax:  # (payload array byte)
16592     0x11/imm32/alloc-id:fake:payload
16593     # "35/xor-with-eax"
16594     0xf/imm32/size
16595     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
16596 _string_39_compare->:  # (payload array byte)
16597     0x11/imm32/alloc-id:fake:payload
16598     # "39/compare->"
16599     0xc/imm32/size
16600     0x33/3 0x39/9 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x2d/dash 0x3e/>
16601 _string_3b_compare<-:  # (payload array byte)
16602     0x11/imm32/alloc-id:fake:payload
16603     # "3b/compare<-"
16604     0xc/imm32/size
16605     0x33/3 0x62/b 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x3c/< 0x2d/dash
16606 _string_3d_compare_eax_with:  # (payload array byte)
16607     0x11/imm32/alloc-id:fake:payload
16608     # "3d/compare-eax-with"
16609     0x13/imm32/size
16610     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
16611 _string_40_increment_eax:  # (payload array byte)
16612     0x11/imm32/alloc-id:fake:payload
16613     # "40/increment-eax"
16614     0x10/imm32/size
16615     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
16616 _string_41_increment_ecx:  # (payload array byte)
16617     0x11/imm32/alloc-id:fake:payload
16618     # "41/increment-ecx"
16619     0x10/imm32/size
16620     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
16621 _string_42_increment_edx:  # (payload array byte)
16622     0x11/imm32/alloc-id:fake:payload
16623     # "42/increment-edx"
16624     0x10/imm32/size
16625     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
16626 _string_43_increment_ebx:  # (payload array byte)
16627     0x11/imm32/alloc-id:fake:payload
16628     # "43/increment-ebx"
16629     0x10/imm32/size
16630     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
16631 _string_46_increment_esi:  # (payload array byte)
16632     0x11/imm32/alloc-id:fake:payload
16633     # "46/increment-esi"
16634     0x10/imm32/size
16635     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
16636 _string_47_increment_edi:  # (payload array byte)
16637     0x11/imm32/alloc-id:fake:payload
16638     # "47/increment-edi"
16639     0x10/imm32/size
16640     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
16641 _string_48_decrement_eax:  # (payload array byte)
16642     0x11/imm32/alloc-id:fake:payload
16643     # "48/decrement-eax"
16644     0x10/imm32/size
16645     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
16646 _string_49_decrement_ecx:  # (payload array byte)
16647     0x11/imm32/alloc-id:fake:payload
16648     # "49/decrement-ecx"
16649     0x10/imm32/size
16650     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
16651 _string_4a_decrement_edx:  # (payload array byte)
16652     0x11/imm32/alloc-id:fake:payload
16653     # "4a/decrement-edx"
16654     0x10/imm32/size
16655     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
16656 _string_4b_decrement_ebx:  # (payload array byte)
16657     0x11/imm32/alloc-id:fake:payload
16658     # "4b/decrement-ebx"
16659     0x10/imm32/size
16660     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
16661 _string_4e_decrement_esi:  # (payload array byte)
16662     0x11/imm32/alloc-id:fake:payload
16663     # "4e/decrement-esi"
16664     0x10/imm32/size
16665     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
16666 _string_4f_decrement_edi:  # (payload array byte)
16667     0x11/imm32/alloc-id:fake:payload
16668     # "4f/decrement-edi"
16669     0x10/imm32/size
16670     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
16671 _string_81_subop_add:  # (payload array byte)
16672     0x11/imm32/alloc-id:fake:payload
16673     # "81 0/subop/add"
16674     0xe/imm32/size
16675     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
16676 _string_81_subop_or:  # (payload array byte)
16677     0x11/imm32/alloc-id:fake:payload
16678     # "81 1/subop/or"
16679     0xd/imm32/size
16680     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
16681 _string_81_subop_and:  # (payload array byte)
16682     0x11/imm32/alloc-id:fake:payload
16683     # "81 4/subop/and"
16684     0xe/imm32/size
16685     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
16686 _string_81_subop_subtract:  # (payload array byte)
16687     0x11/imm32/alloc-id:fake:payload
16688     # "81 5/subop/subtract"
16689     0x13/imm32/size
16690     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
16691 _string_81_subop_xor:  # (payload array byte)
16692     0x11/imm32/alloc-id:fake:payload
16693     # "81 6/subop/xor"
16694     0xe/imm32/size
16695     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
16696 _string_81_subop_compare:  # (payload array byte)
16697     0x11/imm32/alloc-id:fake:payload
16698     # "81 7/subop/compare"
16699     0x12/imm32/size
16700     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
16701 _string_89_<-:  # (payload array byte)
16702     0x11/imm32/alloc-id:fake:payload
16703     # "89/<-"
16704     0x5/imm32/size
16705     0x38/8 0x39/9 0x2f/slash 0x3c/< 0x2d/dash
16706 _string_8b_->:  # (payload array byte)
16707     0x11/imm32/alloc-id:fake:payload
16708     # "8b/->"
16709     0x5/imm32/size
16710     0x38/8 0x62/b 0x2f/slash 0x2d/dash 0x3e/>
16711 _string_8a_copy_byte:
16712     0x11/imm32/alloc-id:fake:payload
16713     # "8a/byte->"
16714     0x9/imm32/size
16715     0x38/8 0x61/a 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x3e/>
16716 _string_88_copy_byte:
16717     0x11/imm32/alloc-id:fake:payload
16718     # "88/byte<-"
16719     0x9/imm32/size
16720     0x38/8 0x38/8 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x3c/< 0x2d/-
16721 _string_8d_copy_address:  # (payload array byte)
16722     0x11/imm32/alloc-id:fake:payload
16723     # "8d/copy-address"
16724     0xf/imm32/size
16725     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
16726 _string_b8_copy_to_eax:  # (payload array byte)
16727     0x11/imm32/alloc-id:fake:payload
16728     # "b8/copy-to-eax"
16729     0xe/imm32/size
16730     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
16731 _string_b9_copy_to_ecx:  # (payload array byte)
16732     0x11/imm32/alloc-id:fake:payload
16733     # "b9/copy-to-ecx"
16734     0xe/imm32/size
16735     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
16736 _string_ba_copy_to_edx:  # (payload array byte)
16737     0x11/imm32/alloc-id:fake:payload
16738     # "ba/copy-to-edx"
16739     0xe/imm32/size
16740     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
16741 _string_bb_copy_to_ebx:  # (payload array byte)
16742     0x11/imm32/alloc-id:fake:payload
16743     # "bb/copy-to-ebx"
16744     0xe/imm32/size
16745     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
16746 _string_be_copy_to_esi:  # (payload array byte)
16747     0x11/imm32/alloc-id:fake:payload
16748     # "be/copy-to-esi"
16749     0xe/imm32/size
16750     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
16751 _string_bf_copy_to_edi:  # (payload array byte)
16752     0x11/imm32/alloc-id:fake:payload
16753     # "bf/copy-to-edi"
16754     0xe/imm32/size
16755     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
16756 _string_c7_subop_copy:  # (payload array byte)
16757     0x11/imm32/alloc-id:fake:payload
16758     # "c7 0/subop/copy"
16759     0xf/imm32/size
16760     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
16761 _string_e9_jump_label:  # (payload array byte)
16762     0x11/imm32/alloc-id:fake:payload
16763     # "e9/jump"
16764     0x7/imm32/size
16765     0x65/e 0x39/9 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p
16766 _string_e9_jump_break:  # (payload array byte)
16767     0x11/imm32/alloc-id:fake:payload
16768     # "e9/jump break/disp32"
16769     0x14/imm32/size
16770     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
16771 _string_e9_jump_loop:  # (payload array byte)
16772     0x11/imm32/alloc-id:fake:payload
16773     # "e9/jump loop/disp32"
16774     0x13/imm32/size
16775     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
16776 _string_ff_subop_increment:  # (payload array byte)
16777     0x11/imm32/alloc-id:fake:payload
16778     # "ff 0/subop/increment"
16779     0x14/imm32/size
16780     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
16781 _string_ff_subop_decrement:  # (payload array byte)
16782     0x11/imm32/alloc-id:fake:payload
16783     # "ff 1/subop/decrement"
16784     0x14/imm32/size
16785     0x66/f 0x66/f 0x31/1 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
16786 
16787 Single-int-var-in-mem:  # (payload list var)
16788     0x11/imm32/alloc-id:fake:payload
16789     0x11/imm32/alloc-id:fake
16790     Int-var-in-mem/imm32
16791     0/imm32/next
16792     0/imm32/next
16793 
16794 Int-var-in-mem:  # (payload var)
16795     0x11/imm32/alloc-id:fake:payload
16796     0/imm32/name
16797     0/imm32/name
16798     0x11/imm32/alloc-id:fake
16799     Type-int/imm32
16800     1/imm32/some-block-depth
16801     1/imm32/some-stack-offset
16802     0/imm32/no-register
16803     0/imm32/no-register
16804 
16805 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
16806 Single-byte-var-in-mem:  # (payload list var)
16807     0x11/imm32/alloc-id:fake:payload
16808     0x11/imm32/alloc-id:fake
16809     Byte-var-in-mem/imm32
16810     0/imm32/next
16811     0/imm32/next
16812 
16813 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
16814 Byte-var-in-mem:  # (payload var)
16815     0x11/imm32/alloc-id:fake:payload
16816     0/imm32/name
16817     0/imm32/name
16818     0x11/imm32/alloc-id:fake
16819     Type-byte/imm32
16820     1/imm32/some-block-depth
16821     1/imm32/some-stack-offset
16822     0/imm32/no-register
16823     0/imm32/no-register
16824 
16825 Two-args-int-stack-int-reg:  # (payload list var)
16826     0x11/imm32/alloc-id:fake:payload
16827     0x11/imm32/alloc-id:fake
16828     Int-var-in-mem/imm32
16829     0x11/imm32/alloc-id:fake
16830     Single-int-var-in-some-register/imm32/next
16831 
16832 Two-int-args-in-regs:  # (payload list var)
16833     0x11/imm32/alloc-id:fake:payload
16834     0x11/imm32/alloc-id:fake
16835     Int-var-in-some-register/imm32
16836     0x11/imm32/alloc-id:fake
16837     Single-int-var-in-some-register/imm32/next
16838 
16839 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
16840 Two-args-byte-stack-byte-reg:  # (payload list var)
16841     0x11/imm32/alloc-id:fake:payload
16842     0x11/imm32/alloc-id:fake
16843     Byte-var-in-mem/imm32
16844     0x11/imm32/alloc-id:fake
16845     Single-byte-var-in-some-register/imm32/next
16846 
16847 Two-args-int-reg-int-stack:  # (payload list var)
16848     0x11/imm32/alloc-id:fake:payload
16849     0x11/imm32/alloc-id:fake
16850     Int-var-in-some-register/imm32
16851     0x11/imm32/alloc-id:fake
16852     Single-int-var-in-mem/imm32/next
16853 
16854 Two-args-int-eax-int-literal:  # (payload list var)
16855     0x11/imm32/alloc-id:fake:payload
16856     0x11/imm32/alloc-id:fake
16857     Int-var-in-eax/imm32
16858     0x11/imm32/alloc-id:fake
16859     Single-lit-var/imm32/next
16860 
16861 Int-var-and-literal:  # (payload list var)
16862     0x11/imm32/alloc-id:fake:payload
16863     0x11/imm32/alloc-id:fake
16864     Int-var-in-mem/imm32
16865     0x11/imm32/alloc-id:fake
16866     Single-lit-var/imm32/next
16867 
16868 Int-var-in-register-and-literal:  # (payload list var)
16869     0x11/imm32/alloc-id:fake:payload
16870     0x11/imm32/alloc-id:fake
16871     Int-var-in-some-register/imm32
16872     0x11/imm32/alloc-id:fake
16873     Single-lit-var/imm32/next
16874 
16875 Single-int-var-in-some-register:  # (payload list var)
16876     0x11/imm32/alloc-id:fake:payload
16877     0x11/imm32/alloc-id:fake
16878     Int-var-in-some-register/imm32
16879     0/imm32/next
16880     0/imm32/next
16881 
16882 Single-addr-var-in-some-register:  # (payload list var)
16883     0x11/imm32/alloc-id:fake:payload
16884     0x11/imm32/alloc-id:fake
16885     Addr-var-in-some-register/imm32
16886     0/imm32/next
16887     0/imm32/next
16888 
16889 Single-byte-var-in-some-register:  # (payload list var)
16890     0x11/imm32/alloc-id:fake:payload
16891     0x11/imm32/alloc-id:fake
16892     Byte-var-in-some-register/imm32
16893     0/imm32/next
16894     0/imm32/next
16895 
16896 Int-var-in-some-register:  # (payload var)
16897     0x11/imm32/alloc-id:fake:payload
16898     0/imm32/name
16899     0/imm32/name
16900     0x11/imm32/alloc-id:fake
16901     Type-int/imm32
16902     1/imm32/some-block-depth
16903     0/imm32/no-stack-offset
16904     0x11/imm32/alloc-id:fake
16905     Any-register/imm32
16906 
16907 Any-register:  # (payload array byte)
16908     0x11/imm32/alloc-id:fake:payload
16909     1/imm32/size
16910     # data
16911     2a/asterisk
16912 
16913 Addr-var-in-some-register:  # (payload var)
16914     0x11/imm32/alloc-id:fake:payload
16915     0/imm32/name
16916     0/imm32/name
16917     0x11/imm32/alloc-id:fake
16918     Type-addr/imm32
16919     1/imm32/some-block-depth
16920     0/imm32/no-stack-offset
16921     0x11/imm32/alloc-id:fake
16922     Any-register/imm32
16923 
16924 Byte-var-in-some-register:  # (payload var)
16925     0x11/imm32/alloc-id:fake:payload
16926     0/imm32/name
16927     0/imm32/name
16928     0x11/imm32/alloc-id:fake
16929     Type-byte/imm32
16930     1/imm32/some-block-depth
16931     0/imm32/no-stack-offset
16932     0x11/imm32/alloc-id:fake
16933     Any-register/imm32
16934 
16935 Single-int-var-in-eax:  # (payload list var)
16936     0x11/imm32/alloc-id:fake:payload
16937     0x11/imm32/alloc-id:fake
16938     Int-var-in-eax/imm32
16939     0/imm32/next
16940     0/imm32/next
16941 
16942 Int-var-in-eax:
16943     0x11/imm32/alloc-id:fake:payload
16944     0/imm32/name
16945     0/imm32/name
16946     0x11/imm32/alloc-id:fake
16947     Type-int/imm32
16948     1/imm32/some-block-depth
16949     0/imm32/no-stack-offset
16950     0x11/imm32/alloc-id:fake
16951     $Register-eax/imm32
16952 
16953 Single-int-var-in-ecx:  # (payload list var)
16954     0x11/imm32/alloc-id:fake:payload
16955     0x11/imm32/alloc-id:fake
16956     Int-var-in-ecx/imm32
16957     0/imm32/next
16958     0/imm32/next
16959 
16960 Int-var-in-ecx:
16961     0x11/imm32/alloc-id:fake:payload
16962     0/imm32/name
16963     0/imm32/name
16964     0x11/imm32/alloc-id:fake
16965     Type-int/imm32
16966     1/imm32/some-block-depth
16967     0/imm32/no-stack-offset
16968     0x11/imm32/alloc-id:fake
16969     $Register-ecx/imm32/register
16970 
16971 Single-int-var-in-edx:  # (payload list var)
16972     0x11/imm32/alloc-id:fake:payload
16973     0x11/imm32/alloc-id:fake
16974     Int-var-in-edx/imm32
16975     0/imm32/next
16976     0/imm32/next
16977 
16978 Int-var-in-edx:  # (payload list var)
16979     0x11/imm32/alloc-id:fake:payload
16980     0/imm32/name
16981     0/imm32/name
16982     0x11/imm32/alloc-id:fake
16983     Type-int/imm32
16984     1/imm32/some-block-depth
16985     0/imm32/no-stack-offset
16986     0x11/imm32/alloc-id:fake
16987     $Register-edx/imm32/register
16988 
16989 Single-int-var-in-ebx:  # (payload list var)
16990     0x11/imm32/alloc-id:fake:payload
16991     0x11/imm32/alloc-id:fake
16992     Int-var-in-ebx/imm32
16993     0/imm32/next
16994     0/imm32/next
16995 
16996 Int-var-in-ebx:  # (payload list var)
16997     0x11/imm32/alloc-id:fake:payload
16998     0/imm32/name
16999     0/imm32/name
17000     0x11/imm32/alloc-id:fake
17001     Type-int/imm32
17002     1/imm32/some-block-depth
17003     0/imm32/no-stack-offset
17004     0x11/imm32/alloc-id:fake
17005     $Register-ebx/imm32/register
17006 
17007 Single-int-var-in-esi:  # (payload list var)
17008     0x11/imm32/alloc-id:fake:payload
17009     0x11/imm32/alloc-id:fake
17010     Int-var-in-esi/imm32
17011     0/imm32/next
17012     0/imm32/next
17013 
17014 Int-var-in-esi:  # (payload list var)
17015     0x11/imm32/alloc-id:fake:payload
17016     0/imm32/name
17017     0/imm32/name
17018     0x11/imm32/alloc-id:fake
17019     Type-int/imm32
17020     1/imm32/some-block-depth
17021     0/imm32/no-stack-offset
17022     0x11/imm32/alloc-id:fake
17023     $Register-esi/imm32/register
17024 
17025 Single-int-var-in-edi:  # (payload list var)
17026     0x11/imm32/alloc-id:fake:payload
17027     0x11/imm32/alloc-id:fake
17028     Int-var-in-edi/imm32
17029     0/imm32/next
17030     0/imm32/next
17031 
17032 Int-var-in-edi:  # (payload list var)
17033     0x11/imm32/alloc-id:fake:payload
17034     0/imm32/name
17035     0/imm32/name
17036     0x11/imm32/alloc-id:fake
17037     Type-int/imm32
17038     1/imm32/some-block-depth
17039     0/imm32/no-stack-offset
17040     0x11/imm32/alloc-id:fake
17041     $Register-edi/imm32/register
17042 
17043 Single-lit-var:  # (payload list var)
17044     0x11/imm32/alloc-id:fake:payload
17045     0x11/imm32/alloc-id:fake
17046     Lit-var/imm32
17047     0/imm32/next
17048     0/imm32/next
17049 
17050 Lit-var:  # (payload var)
17051     0x11/imm32/alloc-id:fake:payload
17052     0/imm32/name
17053     0/imm32/name
17054     0x11/imm32/alloc-id:fake
17055     Type-literal/imm32
17056     1/imm32/some-block-depth
17057     0/imm32/no-stack-offset
17058     0/imm32/no-register
17059     0/imm32/no-register
17060 
17061 Type-int:  # (payload tree type-id)
17062     0x11/imm32/alloc-id:fake:payload
17063     1/imm32/left-is-atom
17064     1/imm32/value:int
17065     0/imm32/left:unused
17066     0/imm32/right:null
17067     0/imm32/right:null
17068 
17069 Type-literal:  # (payload tree type-id)
17070     0x11/imm32/alloc-id:fake:payload
17071     1/imm32/is-atom
17072     0/imm32/value:literal
17073     0/imm32/left:unused
17074     0/imm32/right:null
17075     0/imm32/right:null
17076 
17077 Type-addr:  # (payload tree type-id)
17078     0x11/imm32/alloc-id:fake:payload
17079     1/imm32/is-atom
17080     2/imm32/value:addr
17081     0/imm32/left:unused
17082     0/imm32/right:null
17083     0/imm32/right:null
17084 
17085 Type-byte:  # (payload tree type-id)
17086     0x11/imm32/alloc-id:fake:payload
17087     1/imm32/is-atom
17088     8/imm32/value:byte
17089     0/imm32/left:unused
17090     0/imm32/right:null
17091     0/imm32/right:null
17092 
17093 == code
17094 emit-subx-primitive:  # out: (addr buffered-file), stmt: (addr stmt), primitive: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
17095     # . prologue
17096     55/push-ebp
17097     89/<- %ebp 4/r32/esp
17098     # . save registers
17099     50/push-eax
17100     51/push-ecx
17101     # ecx = primitive
17102     8b/-> *(ebp+0x10) 1/r32/ecx
17103     # emit primitive name
17104     (emit-indent *(ebp+8) *Curr-block-depth)
17105     (lookup *(ecx+0x18) *(ecx+0x1c))  # Primitive-subx-name Primitive-subx-name => eax
17106     (write-buffered *(ebp+8) %eax)
17107     # emit rm32 if necessary
17108     (emit-subx-rm32 *(ebp+8) *(ecx+0x20) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-rm32
17109     # emit r32 if necessary
17110     (emit-subx-r32 *(ebp+8) *(ecx+0x24) *(ebp+0xc))  # Primitive-subx-r32
17111     # emit imm32 if necessary
17112     (emit-subx-imm32 *(ebp+8) *(ecx+0x28) *(ebp+0xc))  # Primitive-subx-imm32
17113     # emit disp32 if necessary
17114     (emit-subx-disp32 *(ebp+8) *(ecx+0x2c) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-disp32
17115     (write-buffered *(ebp+8) Newline)
17116 $emit-subx-primitive:end:
17117     # . restore registers
17118     59/pop-to-ecx
17119     58/pop-to-eax
17120     # . epilogue
17121     89/<- %esp 5/r32/ebp
17122     5d/pop-to-ebp
17123     c3/return
17124 
17125 emit-subx-rm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
17126     # . prologue
17127     55/push-ebp
17128     89/<- %ebp 4/r32/esp
17129     # . save registers
17130     50/push-eax
17131     # if (l == 0) return
17132     81 7/subop/compare *(ebp+0xc) 0/imm32
17133     74/jump-if-= $emit-subx-rm32:end/disp8
17134     # var v/eax: (addr stmt-var)
17135     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
17136     (emit-subx-var-as-rm32 *(ebp+8) %eax)
17137 $emit-subx-rm32:end:
17138     # . restore registers
17139     58/pop-to-eax
17140     # . epilogue
17141     89/<- %esp 5/r32/ebp
17142     5d/pop-to-ebp
17143     c3/return
17144 
17145 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)
17146     # . prologue
17147     55/push-ebp
17148     89/<- %ebp 4/r32/esp
17149     # . save registers
17150     51/push-ecx
17151     # eax = l
17152     8b/-> *(ebp+0xc) 0/r32/eax
17153     # ecx = stmt
17154     8b/-> *(ebp+8) 1/r32/ecx
17155     # if (l == 1) return stmt->inouts
17156     {
17157       3d/compare-eax-and 1/imm32
17158       75/jump-if-!= break/disp8
17159 $get-stmt-operand-from-arg-location:1:
17160       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17161       eb/jump $get-stmt-operand-from-arg-location:end/disp8
17162     }
17163     # if (l == 2) return stmt->inouts->next
17164     {
17165       3d/compare-eax-and 2/imm32
17166       75/jump-if-!= break/disp8
17167 $get-stmt-operand-from-arg-location:2:
17168       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17169       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
17170       eb/jump $get-stmt-operand-from-arg-location:end/disp8
17171     }
17172     # if (l == 3) return stmt->outputs
17173     {
17174       3d/compare-eax-and 3/imm32
17175       75/jump-if-!= break/disp8
17176 $get-stmt-operand-from-arg-location:3:
17177       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
17178       eb/jump $get-stmt-operand-from-arg-location:end/disp8
17179     }
17180     # abort
17181     e9/jump $get-stmt-operand-from-arg-location:abort/disp32
17182 $get-stmt-operand-from-arg-location:end:
17183     # . restore registers
17184     59/pop-to-ecx
17185     # . epilogue
17186     89/<- %esp 5/r32/ebp
17187     5d/pop-to-ebp
17188     c3/return
17189 
17190 $get-stmt-operand-from-arg-location:abort:
17191     # error("invalid arg-location " eax)
17192     (write-buffered *(ebp+0x10) "invalid arg-location ")
17193     (write-int32-hex-buffered *(ebp+0x10) %eax)
17194     (write-buffered *(ebp+0x10) Newline)
17195     (flush *(ebp+0x10))
17196     (stop *(ebp+0x14) 1)
17197     # never gets here
17198 
17199 emit-subx-r32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
17200     # . prologue
17201     55/push-ebp
17202     89/<- %ebp 4/r32/esp
17203     # . save registers
17204     50/push-eax
17205     51/push-ecx
17206     # if (l == 0) return
17207     81 7/subop/compare *(ebp+0xc) 0/imm32
17208     0f 84/jump-if-= $emit-subx-r32:end/disp32
17209     # var v/eax: (addr stmt-var)
17210     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
17211     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17212     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
17213     (maybe-get Mu-registers %eax 0xc)  # => eax: (addr register-index)
17214     (write-buffered *(ebp+8) Space)
17215     (write-int32-hex-buffered *(ebp+8) *eax)
17216     (write-buffered *(ebp+8) "/r32")
17217 $emit-subx-r32:end:
17218     # . restore registers
17219     59/pop-to-ecx
17220     58/pop-to-eax
17221     # . epilogue
17222     89/<- %esp 5/r32/ebp
17223     5d/pop-to-ebp
17224     c3/return
17225 
17226 emit-subx-imm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
17227     # . prologue
17228     55/push-ebp
17229     89/<- %ebp 4/r32/esp
17230     # . save registers
17231     50/push-eax
17232     51/push-ecx
17233     # if (l == 0) return
17234     81 7/subop/compare *(ebp+0xc) 0/imm32
17235     0f 84/jump-if-= $emit-subx-imm32:end/disp32
17236     # var v/eax: (handle var)
17237     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
17238     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17239     (lookup *eax *(eax+4))  # Var-name Var-name => eax
17240     (write-buffered *(ebp+8) Space)
17241     (write-buffered *(ebp+8) %eax)
17242     (write-buffered *(ebp+8) "/imm32")
17243 $emit-subx-imm32:end:
17244     # . restore registers
17245     59/pop-to-ecx
17246     58/pop-to-eax
17247     # . epilogue
17248     89/<- %esp 5/r32/ebp
17249     5d/pop-to-ebp
17250     c3/return
17251 
17252 emit-subx-disp32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
17253     # . prologue
17254     55/push-ebp
17255     89/<- %ebp 4/r32/esp
17256     # . save registers
17257     50/push-eax
17258     51/push-ecx
17259     # if (location == 0) return
17260     81 7/subop/compare *(ebp+0xc) 0/imm32
17261     0f 84/jump-if-= $emit-subx-disp32:end/disp32
17262     # var v/eax: (addr stmt-var)
17263     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
17264     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17265     (lookup *eax *(eax+4))  # Var-name Var-name => eax
17266     (write-buffered *(ebp+8) Space)
17267     (write-buffered *(ebp+8) %eax)
17268     # hack: if instruction operation starts with "break", emit ":break"
17269     # var name/ecx: (addr array byte) = lookup(stmt->operation)
17270     8b/-> *(ebp+0x10) 0/r32/eax
17271     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
17272     89/<- %ecx 0/r32/eax
17273     {
17274       (string-starts-with? %ecx "break")  # => eax
17275       3d/compare-eax-and 0/imm32/false
17276       74/jump-if-= break/disp8
17277       (write-buffered *(ebp+8) ":break")
17278     }
17279     # hack: if instruction operation starts with "loop", emit ":loop"
17280     {
17281       (string-starts-with? %ecx "loop")  # => eax
17282       3d/compare-eax-and 0/imm32/false
17283       74/jump-if-= break/disp8
17284       (write-buffered *(ebp+8) ":loop")
17285     }
17286     (write-buffered *(ebp+8) "/disp32")
17287 $emit-subx-disp32:end:
17288     # . restore registers
17289     59/pop-to-ecx
17290     58/pop-to-eax
17291     # . epilogue
17292     89/<- %esp 5/r32/ebp
17293     5d/pop-to-ebp
17294     c3/return
17295 
17296 emit-call:  # out: (addr buffered-file), stmt: (addr stmt)
17297     # . prologue
17298     55/push-ebp
17299     89/<- %ebp 4/r32/esp
17300     # . save registers
17301     50/push-eax
17302     51/push-ecx
17303     #
17304     (emit-indent *(ebp+8) *Curr-block-depth)
17305     (write-buffered *(ebp+8) "(")
17306     # ecx = stmt
17307     8b/-> *(ebp+0xc) 1/r32/ecx
17308     # - emit function name
17309     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
17310     (write-buffered *(ebp+8) %eax)
17311     # - emit arguments
17312     # var curr/eax: (addr stmt-var) = lookup(stmt->inouts)
17313     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17314     {
17315       # if (curr == null) break
17316       3d/compare-eax-and 0/imm32
17317       74/jump-if-= break/disp8
17318       #
17319       (emit-subx-call-operand *(ebp+8) %eax)
17320       # curr = lookup(curr->next)
17321       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
17322       eb/jump loop/disp8
17323     }
17324     #
17325     (write-buffered *(ebp+8) ")\n")
17326 $emit-call:end:
17327     # . restore registers
17328     59/pop-to-ecx
17329     58/pop-to-eax
17330     # . epilogue
17331     89/<- %esp 5/r32/ebp
17332     5d/pop-to-ebp
17333     c3/return
17334 
17335 emit-subx-call-operand:  # out: (addr buffered-file), s: (addr stmt-var)
17336     # shares code with emit-subx-var-as-rm32
17337     # . prologue
17338     55/push-ebp
17339     89/<- %ebp 4/r32/esp
17340     # . save registers
17341     50/push-eax
17342     51/push-ecx
17343     56/push-esi
17344     # ecx = s
17345     8b/-> *(ebp+0xc) 1/r32/ecx
17346     # var operand/esi: (addr var) = lookup(s->value)
17347     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
17348     89/<- %esi 0/r32/eax
17349     # if (operand->register && !s->is-deref?) emit "%__"
17350     {
17351 $emit-subx-call-operand:check-for-register-direct:
17352       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
17353       74/jump-if-= break/disp8
17354       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
17355       75/jump-if-!= break/disp8
17356 $emit-subx-call-operand:register-direct:
17357       (write-buffered *(ebp+8) " %")
17358       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
17359       (write-buffered *(ebp+8) %eax)
17360       e9/jump $emit-subx-call-operand:end/disp32
17361     }
17362     # else if (operand->register && s->is-deref?) emit "*__"
17363     {
17364 $emit-subx-call-operand:check-for-register-indirect:
17365       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
17366       74/jump-if-= break/disp8
17367       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
17368       74/jump-if-= break/disp8
17369 $emit-subx-call-operand:register-indirect:
17370       (emit-subx-call-operand-register-indirect *(ebp+8) %esi)
17371       e9/jump $emit-subx-call-operand:end/disp32
17372     }
17373     # else if (operand->stack-offset) emit "*(ebp+__)"
17374     {
17375       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
17376       74/jump-if-= break/disp8
17377 $emit-subx-call-operand:stack:
17378       (emit-subx-call-operand-stack *(ebp+8) %esi)
17379       e9/jump $emit-subx-call-operand:end/disp32
17380     }
17381     # else if (operand->type == literal) emit "__"
17382     {
17383       (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
17384       81 7/subop/compare *(eax+4) 0/imm32  # Tree-left
17385       75/jump-if-!= break/disp8
17386 $emit-subx-call-operand:literal:
17387       (write-buffered *(ebp+8) Space)
17388       (lookup *esi *(esi+4))  # Var-name Var-name => eax
17389       (write-buffered *(ebp+8) %eax)
17390     }
17391 $emit-subx-call-operand:end:
17392     # . restore registers
17393     5e/pop-to-esi
17394     59/pop-to-ecx
17395     58/pop-to-eax
17396     # . epilogue
17397     89/<- %esp 5/r32/ebp
17398     5d/pop-to-ebp
17399     c3/return
17400 
17401 emit-subx-call-operand-register-indirect:  # out: (addr buffered-file), v: (addr var)
17402     # . prologue
17403     55/push-ebp
17404     89/<- %ebp 4/r32/esp
17405     # . save registers
17406     50/push-eax
17407     51/push-ecx
17408     56/push-esi
17409     # esi = v
17410     8b/-> *(ebp+0xc) 6/r32/esi
17411     # var size/ecx: int = size-of-deref(v)
17412     (size-of-deref %esi)  # => eax
17413     89/<- %ecx 0/r32/eax
17414     # var reg-name/esi: (addr array byte) = lookup(v->register)
17415     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
17416     89/<- %esi 0/r32/eax
17417     # TODO: assert size is a multiple of 4
17418     # var i/eax: int = 0
17419     b8/copy-to-eax 0/imm32
17420     {
17421 $emit-subx-call-operand-register-indirect:loop:
17422       # if (i >= size) break
17423       39/compare %eax 1/r32/ecx
17424       7d/jump-if->= break/disp8
17425       # emit " *(" v->register "+" i ")"
17426       (write-buffered *(ebp+8) " *(")
17427       (write-buffered *(ebp+8) %esi)
17428       (write-buffered *(ebp+8) "+")
17429       (write-int32-hex-buffered *(ebp+8) %eax)
17430       (write-buffered *(ebp+8) ")")
17431       # i += 4
17432       05/add-to-eax 4/imm32
17433       #
17434       eb/jump loop/disp8
17435     }
17436 $emit-subx-call-operand-register-indirect:end:
17437     # . restore registers
17438     5e/pop-to-esi
17439     59/pop-to-ecx
17440     58/pop-to-eax
17441     # . epilogue
17442     89/<- %esp 5/r32/ebp
17443     5d/pop-to-ebp
17444     c3/return
17445 
17446 emit-subx-call-operand-stack:  # out: (addr buffered-file), v: (addr var)
17447     # . prologue
17448     55/push-ebp
17449     89/<- %ebp 4/r32/esp
17450     # . save registers
17451     50/push-eax
17452     51/push-ecx
17453     56/push-esi
17454     # esi = v
17455     8b/-> *(ebp+0xc) 6/r32/esi
17456     # var curr/ecx: int = v->offset
17457     8b/-> *(esi+0x14) 1/r32/ecx  # Var-offset
17458     # var max/eax: int = v->offset + size-of(v)
17459     (size-of %esi)  # => eax
17460     # TODO: assert size is a multiple of 4
17461     01/add-to %eax 1/r32/ecx
17462     {
17463 $emit-subx-call-operand-stack:loop:
17464       # if (curr >= max) break
17465       39/compare %ecx 0/r32/eax
17466       7d/jump-if->= break/disp8
17467       # emit " *(ebp+" curr ")"
17468       (write-buffered *(ebp+8) " *(ebp+")
17469       (write-int32-hex-buffered *(ebp+8) %ecx)
17470       (write-buffered *(ebp+8) ")")
17471       # i += 4
17472       81 0/subop/add %ecx 4/imm32
17473       #
17474       eb/jump loop/disp8
17475     }
17476 $emit-subx-call-operand-stack:end:
17477     # . restore registers
17478     5e/pop-to-esi
17479     59/pop-to-ecx
17480     58/pop-to-eax
17481     # . epilogue
17482     89/<- %esp 5/r32/ebp
17483     5d/pop-to-ebp
17484     c3/return
17485 
17486 emit-subx-var-as-rm32:  # out: (addr buffered-file), s: (addr stmt-var)
17487     # . prologue
17488     55/push-ebp
17489     89/<- %ebp 4/r32/esp
17490     # . save registers
17491     50/push-eax
17492     51/push-ecx
17493     56/push-esi
17494     # ecx = s
17495     8b/-> *(ebp+0xc) 1/r32/ecx
17496     # var operand/esi: (addr var) = lookup(s->value)
17497     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
17498     89/<- %esi 0/r32/eax
17499     # if (operand->register && s->is-deref?) emit "*__"
17500     {
17501 $emit-subx-var-as-rm32:check-for-register-indirect:
17502       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
17503       74/jump-if-= break/disp8
17504       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
17505       74/jump-if-= break/disp8
17506 $emit-subx-var-as-rm32:register-indirect:
17507       (write-buffered *(ebp+8) " *")
17508       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
17509       (write-buffered *(ebp+8) %eax)
17510       e9/jump $emit-subx-var-as-rm32:end/disp32
17511     }
17512     # if (operand->register && !s->is-deref?) emit "%__"
17513     {
17514 $emit-subx-var-as-rm32:check-for-register-direct:
17515       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
17516       74/jump-if-= break/disp8
17517       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
17518       75/jump-if-!= break/disp8
17519 $emit-subx-var-as-rm32:register-direct:
17520       (write-buffered *(ebp+8) " %")
17521       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
17522       (write-buffered *(ebp+8) %eax)
17523       e9/jump $emit-subx-var-as-rm32:end/disp32
17524     }
17525     # else if (operand->stack-offset) emit "*(ebp+__)"
17526     {
17527       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
17528       74/jump-if-= break/disp8
17529 $emit-subx-var-as-rm32:stack:
17530       (write-buffered *(ebp+8) Space)
17531       (write-buffered *(ebp+8) "*(ebp+")
17532       (write-int32-hex-buffered *(ebp+8) *(esi+0x14))  # Var-offset
17533       (write-buffered *(ebp+8) ")")
17534     }
17535 $emit-subx-var-as-rm32:end:
17536     # . restore registers
17537     5e/pop-to-esi
17538     59/pop-to-ecx
17539     58/pop-to-eax
17540     # . epilogue
17541     89/<- %esp 5/r32/ebp
17542     5d/pop-to-ebp
17543     c3/return
17544 
17545 find-matching-primitive:  # primitives: (addr primitive), stmt: (addr stmt) -> result/eax: (addr primitive)
17546     # . prologue
17547     55/push-ebp
17548     89/<- %ebp 4/r32/esp
17549     # . save registers
17550     51/push-ecx
17551     # var curr/ecx: (addr primitive) = primitives
17552     8b/-> *(ebp+8) 1/r32/ecx
17553     {
17554 $find-matching-primitive:loop:
17555       # if (curr == null) break
17556       81 7/subop/compare %ecx 0/imm32
17557       74/jump-if-= break/disp8
17558       # if match(curr, stmt) return curr
17559       {
17560         (mu-stmt-matches-primitive? *(ebp+0xc) %ecx)  # => eax
17561         3d/compare-eax-and 0/imm32/false
17562         74/jump-if-= break/disp8
17563         89/<- %eax 1/r32/ecx
17564         eb/jump $find-matching-primitive:end/disp8
17565       }
17566 $find-matching-primitive:next-primitive:
17567       # curr = curr->next
17568       (lookup *(ecx+0x34) *(ecx+0x38))  # Primitive-next Primitive-next => eax
17569       89/<- %ecx 0/r32/eax
17570       #
17571       e9/jump loop/disp32
17572     }
17573     # return null
17574     b8/copy-to-eax 0/imm32
17575 $find-matching-primitive:end:
17576     # . restore registers
17577     59/pop-to-ecx
17578     # . epilogue
17579     89/<- %esp 5/r32/ebp
17580     5d/pop-to-ebp
17581     c3/return
17582 
17583 mu-stmt-matches-primitive?:  # stmt: (addr stmt), primitive: (addr primitive) -> result/eax: boolean
17584     # A mu stmt matches a primitive if the name matches, all the inout vars
17585     # match, and all the output vars match.
17586     # Vars match if types match and registers match.
17587     # In addition, a stmt output matches a primitive's output if types match
17588     # and the primitive has a wildcard register.
17589     # . prologue
17590     55/push-ebp
17591     89/<- %ebp 4/r32/esp
17592     # . save registers
17593     51/push-ecx
17594     52/push-edx
17595     53/push-ebx
17596     56/push-esi
17597     57/push-edi
17598     # ecx = stmt
17599     8b/-> *(ebp+8) 1/r32/ecx
17600     # edx = primitive
17601     8b/-> *(ebp+0xc) 2/r32/edx
17602     {
17603 $mu-stmt-matches-primitive?:check-name:
17604       # if (primitive->name != stmt->operation) return false
17605       # . var esi: (addr array byte) = lookup(stmt->operation)
17606       (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
17607       89/<- %esi 0/r32/eax
17608       # . var edi: (addr array byte) = lookup(primitive->name)
17609       (lookup *edx *(edx+4))  # Primitive-name Primitive-name => eax
17610       89/<- %edi 0/r32/eax
17611       (string-equal? %esi %edi)  # => eax
17612       3d/compare-eax-and 0/imm32/false
17613       75/jump-if-!= break/disp8
17614       b8/copy-to-eax 0/imm32
17615       e9/jump $mu-stmt-matches-primitive?:end/disp32
17616     }
17617     # var curr/esi: (addr stmt-var) = lookup(stmt->inouts)
17618     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17619     89/<- %esi 0/r32/eax
17620     # var curr2/edi: (addr list var) = lookup(primitive->inouts)
17621     (lookup *(edx+8) *(edx+0xc))  # Primitive-inouts Primitive-inouts => eax
17622     89/<- %edi 0/r32/eax
17623     {
17624 $mu-stmt-matches-primitive?:inouts-loop:
17625       # if (curr == 0 && curr2 == 0) move on to check outputs
17626       {
17627 $mu-stmt-matches-primitive?:check-both-inouts-null:
17628         81 7/subop/compare %esi 0/imm32
17629         75/jump-if-!= break/disp8
17630 $mu-stmt-matches-primitive?:stmt-inout-null:
17631         81 7/subop/compare %edi 0/imm32
17632         0f 84/jump-if-= $mu-stmt-matches-primitive?:check-outputs/disp32
17633 $mu-stmt-matches-primitive?:stmt-inout-null-and-prim-inout-not-null:
17634         # return false
17635         b8/copy-to-eax 0/imm32/false
17636         e9/jump $mu-stmt-matches-primitive?:end/disp32
17637       }
17638       # if (curr2 == 0) return false
17639       {
17640 $mu-stmt-matches-primitive?:check-prim-inout-null:
17641         81 7/subop/compare %edi 0/imm32
17642         75/jump-if-!= break/disp8
17643 $mu-stmt-matches-primitive?:prim-inout-null:
17644         b8/copy-to-eax 0/imm32/false
17645         e9/jump $mu-stmt-matches-primitive?:end/disp32
17646       }
17647       # if (curr != curr2) return false
17648       {
17649 $mu-stmt-matches-primitive?:check-inouts-match:
17650         (lookup *edi *(edi+4))  # List-value List-value => eax
17651         (operand-matches-primitive? %esi %eax)  # => eax
17652         3d/compare-eax-and 0/imm32/false
17653         75/jump-if-!= break/disp8
17654 $mu-stmt-matches-primitive?:inouts-match:
17655         b8/copy-to-eax 0/imm32/false
17656         e9/jump $mu-stmt-matches-primitive?:end/disp32
17657       }
17658 $mu-stmt-matches-primitive?:next-inout:
17659       # curr = lookup(curr->next)
17660       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
17661       89/<- %esi 0/r32/eax
17662       # curr2 = lookup(curr2->next)
17663       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
17664       89/<- %edi 0/r32/eax
17665       #
17666       e9/jump loop/disp32
17667     }
17668 $mu-stmt-matches-primitive?:check-outputs:
17669     # var curr/esi: (addr stmt-var) = lookup(stmt->outputs)
17670     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
17671     89/<- %esi 0/r32/eax
17672     # var curr2/edi: (addr list var) = lookup(primitive->outputs)
17673     (lookup *(edx+0x10) *(edx+0x14))  # Primitive-outputs Primitive-outputs => eax
17674     89/<- %edi 0/r32/eax
17675     {
17676 $mu-stmt-matches-primitive?:outputs-loop:
17677       # if (curr == 0) return (curr2 == 0)
17678       {
17679 $mu-stmt-matches-primitive?:check-both-outputs-null:
17680         81 7/subop/compare %esi 0/imm32
17681         75/jump-if-!= break/disp8
17682         {
17683 $mu-stmt-matches-primitive?:stmt-output-null:
17684           81 7/subop/compare %edi 0/imm32
17685           75/jump-if-!= break/disp8
17686 $mu-stmt-matches-primitive?:both-outputs-null:
17687           # return true
17688           b8/copy-to-eax 1/imm32
17689           e9/jump $mu-stmt-matches-primitive?:end/disp32
17690         }
17691 $mu-stmt-matches-primitive?:stmt-output-null-and-prim-output-not-null:
17692         # return false
17693         b8/copy-to-eax 0/imm32
17694         e9/jump $mu-stmt-matches-primitive?:end/disp32
17695       }
17696       # if (curr2 == 0) return false
17697       {
17698 $mu-stmt-matches-primitive?:check-prim-output-null:
17699         81 7/subop/compare %edi 0/imm32
17700         75/jump-if-!= break/disp8
17701 $mu-stmt-matches-primitive?:prim-output-is-null:
17702         b8/copy-to-eax 0/imm32
17703         e9/jump $mu-stmt-matches-primitive?:end/disp32
17704       }
17705       # if (curr != curr2) return false
17706       {
17707 $mu-stmt-matches-primitive?:check-outputs-match:
17708         (lookup *edi *(edi+4))  # List-value List-value => eax
17709         (operand-matches-primitive? %esi %eax)  # => eax
17710         3d/compare-eax-and 0/imm32/false
17711         75/jump-if-!= break/disp8
17712 $mu-stmt-matches-primitive?:outputs-match:
17713         b8/copy-to-eax 0/imm32
17714         e9/jump $mu-stmt-matches-primitive?:end/disp32
17715       }
17716 $mu-stmt-matches-primitive?:next-output:
17717       # curr = lookup(curr->next)
17718       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
17719       89/<- %esi 0/r32/eax
17720       # curr2 = lookup(curr2->next)
17721       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
17722       89/<- %edi 0/r32/eax
17723       #
17724       e9/jump loop/disp32
17725     }
17726 $mu-stmt-matches-primitive?:return-true:
17727     b8/copy-to-eax 1/imm32
17728 $mu-stmt-matches-primitive?:end:
17729     # . restore registers
17730     5f/pop-to-edi
17731     5e/pop-to-esi
17732     5b/pop-to-ebx
17733     5a/pop-to-edx
17734     59/pop-to-ecx
17735     # . epilogue
17736     89/<- %esp 5/r32/ebp
17737     5d/pop-to-ebp
17738     c3/return
17739 
17740 operand-matches-primitive?:  # s: (addr stmt-var), prim-var: (addr var) -> result/eax: boolean
17741     # . prologue
17742     55/push-ebp
17743     89/<- %ebp 4/r32/esp
17744     # . save registers
17745     51/push-ecx
17746     52/push-edx
17747     53/push-ebx
17748     56/push-esi
17749     57/push-edi
17750     # ecx = s
17751     8b/-> *(ebp+8) 1/r32/ecx
17752     # var var/esi: (addr var) = lookup(s->value)
17753     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
17754     89/<- %esi 0/r32/eax
17755     # edi = prim-var
17756     8b/-> *(ebp+0xc) 7/r32/edi
17757 $operand-matches-primitive?:check-type:
17758     # if !category-match?(var->type, prim-var->type) return false
17759     # . var vtype/ebx: (addr tree type-id) = lookup(var->type)
17760     (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
17761     89/<- %ebx 0/r32/eax
17762     # . var ptype/eax: (addr tree type-id) = lookup(prim-var->type)
17763     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
17764     (subx-type-category-match? %ebx %eax)  # => eax
17765     3d/compare-eax-and 0/imm32/false
17766     0f 84/jump-if-= $operand-matches-primitive?:return-false/disp32
17767     {
17768 $operand-matches-primitive?:check-register:
17769       # if prim-var is in memory and var is in register but dereference, match
17770       {
17771         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
17772         0f 85/jump-if-!= break/disp32
17773         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
17774         74/jump-if-= break/disp8
17775         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
17776         74/jump-if-= break/disp8
17777 $operand-matches-primitive?:var-deref-match:
17778         e9/jump $operand-matches-primitive?:return-true/disp32
17779       }
17780       # if prim-var is in register and var is in register but dereference, no match
17781       {
17782         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
17783         0f 84/jump-if-= break/disp32
17784         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
17785         0f 84/jump-if-= break/disp32
17786         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
17787         74/jump-if-= break/disp8
17788 $operand-matches-primitive?:var-deref-no-match:
17789         e9/jump $operand-matches-primitive?:return-false/disp32
17790       }
17791       # return false if var->register doesn't match prim-var->register
17792       {
17793         # if register addresses are equal, it's a match
17794         # var vreg/ebx: (addr array byte) = lookup(var->register)
17795         (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
17796         89/<- %ebx 0/r32/eax
17797         # var preg/ecx: (addr array byte) = lookup(prim-var->register)
17798         (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
17799         89/<- %ecx 0/r32/eax
17800         # if (vreg == preg) break
17801         39/compare %ecx 3/r32/ebx
17802         74/jump-if-= break/disp8
17803 $operand-matches-primitive?:var-register-no-match:
17804         # if either address is 0, return false
17805         81 7/subop/compare %ebx 0/imm32
17806         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
17807         81 7/subop/compare %ecx 0/imm32
17808         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
17809         # if prim-var->register is wildcard, it's a match
17810         (string-equal? %ecx "*")  # Any-register => eax
17811         3d/compare-eax-and 0/imm32/false
17812         75/jump-if-!= break/disp8
17813 $operand-matches-primitive?:wildcard-no-match:
17814         # if string contents aren't equal, return false
17815         (string-equal? %ecx %ebx)  # => eax
17816         3d/compare-eax-and 0/imm32/false
17817         74/jump-if-= $operand-matches-primitive?:return-false/disp8
17818       }
17819     }
17820 $operand-matches-primitive?:return-true:
17821     b8/copy-to-eax 1/imm32/true
17822     eb/jump $operand-matches-primitive?:end/disp8
17823 $operand-matches-primitive?:return-false:
17824     b8/copy-to-eax 0/imm32/false
17825 $operand-matches-primitive?:end:
17826     # . restore registers
17827     5f/pop-to-edi
17828     5e/pop-to-esi
17829     5b/pop-to-ebx
17830     5a/pop-to-edx
17831     59/pop-to-ecx
17832     # . epilogue
17833     89/<- %esp 5/r32/ebp
17834     5d/pop-to-ebp
17835     c3/return
17836 
17837 find-matching-function:  # functions: (addr function), stmt: (addr stmt) -> result/eax: (addr function)
17838     # . prologue
17839     55/push-ebp
17840     89/<- %ebp 4/r32/esp
17841     # . save registers
17842     51/push-ecx
17843     # var curr/ecx: (handle function) = functions
17844     8b/-> *(ebp+8) 1/r32/ecx
17845     {
17846       # if (curr == null) break
17847       81 7/subop/compare %ecx 0/imm32
17848       74/jump-if-= break/disp8
17849 #?       (write-buffered Stderr "iter\n")
17850 #?       (flush Stderr)
17851       # if match(stmt, curr) return curr
17852       {
17853         (mu-stmt-matches-function? *(ebp+0xc) %ecx)  # => eax
17854         3d/compare-eax-and 0/imm32/false
17855         74/jump-if-= break/disp8
17856         89/<- %eax 1/r32/ecx
17857         eb/jump $find-matching-function:end/disp8
17858       }
17859       # curr = curr->next
17860       (lookup *(ecx+0x20) *(ecx+0x24))  # Function-next Function-next => eax
17861       89/<- %ecx 0/r32/eax
17862       #
17863       eb/jump loop/disp8
17864     }
17865     # return null
17866     b8/copy-to-eax 0/imm32
17867 $find-matching-function:end:
17868     # . restore registers
17869     59/pop-to-ecx
17870     # . epilogue
17871     89/<- %esp 5/r32/ebp
17872     5d/pop-to-ebp
17873     c3/return
17874 
17875 # Just compare names; user-defined functions don't support overloading yet.
17876 mu-stmt-matches-function?:  # stmt: (addr stmt1), function: (addr function) -> result/eax: boolean
17877     # . prologue
17878     55/push-ebp
17879     89/<- %ebp 4/r32/esp
17880     # . save registers
17881     51/push-ecx
17882     # return function->name == stmt->operation
17883     # ecx = lookup(stmt->operation)
17884     8b/-> *(ebp+8) 0/r32/eax
17885     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
17886     89/<- %ecx 0/r32/eax
17887     # eax = lookup(function->name)
17888     8b/-> *(ebp+0xc) 0/r32/eax
17889     (lookup *eax *(eax+4))  # Function-name Function-name => eax
17890     (string-equal? %eax %ecx)  # => eax
17891 $mu-stmt-matches-function?:end:
17892     # . restore registers
17893     59/pop-to-ecx
17894     # . epilogue
17895     89/<- %esp 5/r32/ebp
17896     5d/pop-to-ebp
17897     c3/return
17898 
17899 # Type-checking happens elsewhere. This method is for selecting between
17900 # primitives.
17901 subx-type-category-match?:  # a: (addr tree type-id), b: (addr tree type-id) -> result/eax: boolean
17902     # . prologue
17903     55/push-ebp
17904     89/<- %ebp 4/r32/esp
17905     # . save registers
17906     51/push-ecx
17907     # var alit/ecx: boolean = is-literal-type?(a)
17908     (is-simple-mu-type? *(ebp+8) 0)  # => eax
17909     89/<- %ecx 0/r32/eax
17910     # var blit/eax: boolean = is-literal-type?(b)
17911     (is-simple-mu-type? *(ebp+0xc) 0)  # => eax
17912     # return alit == blit
17913     39/compare %eax 1/r32/ecx
17914     0f 94/set-byte-if-= %al
17915     81 4/subop/and %eax 0xff/imm32
17916 $subx-type-category-match?:end:
17917     # . restore registers
17918     59/pop-to-ecx
17919     # . epilogue
17920     89/<- %esp 5/r32/ebp
17921     5d/pop-to-ebp
17922     c3/return
17923 
17924 is-simple-mu-type?:  # a: (addr tree type-id), n: type-id -> result/eax: boolean
17925     # . prologue
17926     55/push-ebp
17927     89/<- %ebp 4/r32/esp
17928     # . save registers
17929     51/push-ecx
17930     # ecx = n
17931     8b/-> *(ebp+0xc) 1/r32/ecx
17932     # return (a->value == n)
17933     8b/-> *(ebp+8) 0/r32/eax
17934     39/compare *(eax+4) 1/r32/ecx  # Tree-value
17935     0f 94/set-byte-if-= %al
17936     81 4/subop/and %eax 0xff/imm32
17937 $is-simple-mu-type?:end:
17938     # . restore registers
17939     59/pop-to-ecx
17940     # . epilogue
17941     89/<- %esp 5/r32/ebp
17942     5d/pop-to-ebp
17943     c3/return
17944 
17945 is-mu-addr-type?:  # a: (addr tree type-id) -> result/eax: boolean
17946     # . prologue
17947     55/push-ebp
17948     89/<- %ebp 4/r32/esp
17949     # eax = a
17950     8b/-> *(ebp+8) 0/r32/eax
17951     # if (!a->is-atom?) a = a->left
17952     81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
17953     {
17954       75/jump-if-!= break/disp8
17955       (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
17956     }
17957     # return (a->value == addr)
17958     81 7/subop/compare *(eax+4) 2/imm32/addr  # Tree-value
17959     0f 94/set-byte-if-= %al
17960     81 4/subop/and %eax 0xff/imm32
17961 $is-mu-addr-type?:end:
17962     # . epilogue
17963     89/<- %esp 5/r32/ebp
17964     5d/pop-to-ebp
17965     c3/return
17966 
17967 test-emit-subx-stmt-primitive:
17968     # Primitive operation on a variable on the stack.
17969     #   increment foo
17970     # =>
17971     #   ff 0/subop/increment *(ebp-8)
17972     #
17973     # There's a variable on the var stack as follows:
17974     #   name: 'foo'
17975     #   type: int
17976     #   stack-offset: -8
17977     #
17978     # There's a primitive with this info:
17979     #   name: 'increment'
17980     #   inouts: int/mem
17981     #   value: 'ff 0/subop/increment'
17982     #
17983     # . prologue
17984     55/push-ebp
17985     89/<- %ebp 4/r32/esp
17986     # setup
17987     (clear-stream _test-output-stream)
17988     (clear-stream $_test-output-buffered-file->buffer)
17989     # simulate allocated payloads starting with an initial fake alloc-id (0x11)
17990 $test-emit-subx-stmt-primitive:initialize-type:
17991     # var type/ecx: (payload tree type-id) = int
17992     68/push 0/imm32/right:null
17993     68/push 0/imm32/right:null
17994     68/push 0/imm32/left:unused
17995     68/push 1/imm32/value:int
17996     68/push 1/imm32/is-atom?:true
17997     68/push 0x11/imm32/alloc-id:fake:payload
17998     89/<- %ecx 4/r32/esp
17999 $test-emit-subx-stmt-primitive:initialize-var:
18000     # var var-foo/ecx: (payload var) = var(type)
18001     68/push 0/imm32/no-register
18002     68/push 0/imm32/no-register
18003     68/push -8/imm32/stack-offset
18004     68/push 1/imm32/block-depth
18005     51/push-ecx/type
18006     68/push 0x11/imm32/alloc-id:fake
18007     68/push 0/imm32/name
18008     68/push 0/imm32/name
18009     68/push 0x11/imm32/alloc-id:fake:payload
18010     89/<- %ecx 4/r32/esp
18011 $test-emit-subx-stmt-primitive:initialize-var-name:
18012     # var-foo->name = "foo"
18013     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
18014     (copy-array Heap "foo" %eax)
18015 $test-emit-subx-stmt-primitive:initialize-stmt-var:
18016     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
18017     68/push 0/imm32/is-deref:false
18018     68/push 0/imm32/next
18019     68/push 0/imm32/next
18020     51/push-ecx/var-foo
18021     68/push 0x11/imm32/alloc-id:fake
18022     68/push 0x11/imm32/alloc-id:fake:payload
18023     89/<- %ebx 4/r32/esp
18024 $test-emit-subx-stmt-primitive:initialize-stmt:
18025     # var stmt/esi: (addr statement)
18026     68/push 0/imm32/no-outputs
18027     68/push 0/imm32/no-outputs
18028     53/push-ebx/inouts
18029     68/push 0x11/imm32/alloc-id:fake
18030     68/push 0/imm32/operation
18031     68/push 0/imm32/operation
18032     68/push 1/imm32/tag
18033     89/<- %esi 4/r32/esp
18034 $test-emit-subx-stmt-primitive:initialize-stmt-operation:
18035     # stmt->operation = "increment"
18036     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
18037     (copy-array Heap "increment" %eax)
18038 $test-emit-subx-stmt-primitive:initialize-primitive:
18039     # var primitives/ebx: (addr primitive)
18040     68/push 0/imm32/next
18041     68/push 0/imm32/next
18042     68/push 0/imm32/output-is-write-only
18043     68/push 0/imm32/no-disp32
18044     68/push 0/imm32/no-imm32
18045     68/push 0/imm32/no-r32
18046     68/push 1/imm32/rm32-is-first-inout
18047     68/push 0/imm32/subx-name
18048     68/push 0/imm32/subx-name
18049     68/push 0/imm32/no-outputs
18050     68/push 0/imm32/no-outputs
18051     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
18052     68/push 0x11/imm32/alloc-id:fake
18053     68/push 0/imm32/name
18054     68/push 0/imm32/name
18055     89/<- %ebx 4/r32/esp
18056 $test-emit-subx-stmt-primitive:initialize-primitive-name:
18057     # primitives->name = "increment"
18058     (copy-array Heap "increment" %ebx)  # Primitive-name
18059 $test-emit-subx-stmt-primitive:initialize-primitive-subx-name:
18060     # primitives->subx-name = "ff 0/subop/increment"
18061     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
18062     (copy-array Heap "ff 0/subop/increment" %eax)
18063     # convert
18064     c7 0/subop/copy *Curr-block-depth 0/imm32
18065     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
18066     (flush _test-output-buffered-file)
18067 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
18073     # check output
18074     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-stmt-primitive")
18075     # . epilogue
18076     89/<- %esp 5/r32/ebp
18077     5d/pop-to-ebp
18078     c3/return
18079 
18080 test-emit-subx-stmt-primitive-register:
18081     # Primitive operation on a variable in a register.
18082     #   foo <- increment
18083     # =>
18084     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
18085     #
18086     # There's a variable on the var stack as follows:
18087     #   name: 'foo'
18088     #   type: int
18089     #   register: 'eax'
18090     #
18091     # There's a primitive with this info:
18092     #   name: 'increment'
18093     #   out: int/reg
18094     #   value: 'ff 0/subop/increment'
18095     #
18096     # . prologue
18097     55/push-ebp
18098     89/<- %ebp 4/r32/esp
18099     # setup
18100     (clear-stream _test-output-stream)
18101     (clear-stream $_test-output-buffered-file->buffer)
18102 $test-emit-subx-stmt-primitive-register:initialize-type:
18103     # var type/ecx: (payload tree type-id) = int
18104     68/push 0/imm32/right:null
18105     68/push 0/imm32/right:null
18106     68/push 0/imm32/left:unused
18107     68/push 1/imm32/value:int
18108     68/push 1/imm32/is-atom?:true
18109     68/push 0x11/imm32/alloc-id:fake:payload
18110     89/<- %ecx 4/r32/esp
18111 $test-emit-subx-stmt-primitive-register:initialize-var:
18112     # var var-foo/ecx: (payload var)
18113     68/push 0/imm32/register
18114     68/push 0/imm32/register
18115     68/push 0/imm32/no-stack-offset
18116     68/push 1/imm32/block-depth
18117     51/push-ecx
18118     68/push 0x11/imm32/alloc-id:fake
18119     68/push 0/imm32/name
18120     68/push 0/imm32/name
18121     68/push 0x11/imm32/alloc-id:fake:payload
18122     89/<- %ecx 4/r32/esp
18123 $test-emit-subx-stmt-primitive-register:initialize-var-name:
18124     # var-foo->name = "foo"
18125     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
18126     (copy-array Heap "foo" %eax)
18127 $test-emit-subx-stmt-primitive-register:initialize-var-register:
18128     # var-foo->register = "eax"
18129     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
18130     (copy-array Heap "eax" %eax)
18131 $test-emit-subx-stmt-primitive-register:initialize-stmt-var:
18132     # var operand/ebx: (payload stmt-var)
18133     68/push 0/imm32/is-deref:false
18134     68/push 0/imm32/next
18135     68/push 0/imm32/next
18136     51/push-ecx/var-foo
18137     68/push 0x11/imm32/alloc-id:fake
18138     68/push 0x11/imm32/alloc-id:fake:payload
18139     89/<- %ebx 4/r32/esp
18140 $test-emit-subx-stmt-primitive-register:initialize-stmt:
18141     # var stmt/esi: (addr statement)
18142     53/push-ebx/outputs
18143     68/push 0x11/imm32/alloc-id:fake
18144     68/push 0/imm32/no-inouts
18145     68/push 0/imm32/no-inouts
18146     68/push 0/imm32/operation
18147     68/push 0/imm32/operation
18148     68/push 1/imm32
18149     89/<- %esi 4/r32/esp
18150 $test-emit-subx-stmt-primitive-register:initialize-stmt-operation:
18151     # stmt->operation = "increment"
18152     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
18153     (copy-array Heap "increment" %eax)
18154 $test-emit-subx-stmt-primitive-register:initialize-formal-var:
18155     # var formal-var/ebx: (payload var)
18156     68/push 0/imm32/register
18157     68/push 0/imm32/register
18158     68/push 0/imm32/no-stack-offset
18159     68/push 1/imm32/block-depth
18160     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
18161     68/push 0x11/imm32/alloc-id:fake
18162     68/push 0/imm32/name
18163     68/push 0/imm32/name
18164     68/push 0x11/imm32/alloc-id:fake:payload
18165     89/<- %ebx 4/r32/esp
18166 $test-emit-subx-stmt-primitive-register:initialize-formal-var-name:
18167     # formal-var->name = "dummy"
18168     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
18169     (copy-array Heap "dummy" %eax)
18170 $test-emit-subx-stmt-primitive-register:initialize-formal-register:
18171     # formal-var->register = "*"
18172     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
18173     (copy-array Heap "*" %eax)  # Any-register
18174 $test-emit-subx-stmt-primitive-register:initialize-var-list:
18175     # var formal-outputs/ebx: (payload list var)
18176     68/push 0/imm32/next
18177     68/push 0/imm32/next
18178     53/push-ebx/formal-var
18179     68/push 0x11/imm32/alloc-id:fake
18180     68/push 0x11/imm32/alloc-id:fake:payload
18181     89/<- %ebx 4/r32/esp
18182 $test-emit-subx-stmt-primitive-register:initialize-primitive:
18183     # var primitives/ebx: (addr primitive)
18184     68/push 0/imm32/next
18185     68/push 0/imm32/next
18186     68/push 0/imm32/output-is-write-only
18187     68/push 0/imm32/no-disp32
18188     68/push 0/imm32/no-imm32
18189     68/push 0/imm32/no-r32
18190     68/push 3/imm32/rm32-is-first-output
18191     68/push 0/imm32/subx-name
18192     68/push 0/imm32/subx-name
18193     53/push-ebx/outputs
18194     68/push 0x11/imm32/alloc-id:fake
18195     68/push 0/imm32/no-inouts
18196     68/push 0/imm32/no-inouts
18197     68/push 0/imm32/name
18198     68/push 0/imm32/name
18199     89/<- %ebx 4/r32/esp
18200 $test-emit-subx-stmt-primitive-register:initialize-primitive-name:
18201     # primitives->name = "increment"
18202     (copy-array Heap "increment" %ebx)  # Primitive-name
18203 $test-emit-subx-stmt-primitive-register:initialize-primitive-subx-name:
18204     # primitives->subx-name = "ff 0/subop/increment"
18205     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
18206     (copy-array Heap "ff 0/subop/increment" %eax)
18207     # convert
18208     c7 0/subop/copy *Curr-block-depth 0/imm32
18209     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
18210     (flush _test-output-buffered-file)
18211 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
18217     # check output
18218     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-primitive-register")
18219     # . epilogue
18220     89/<- %esp 5/r32/ebp
18221     5d/pop-to-ebp
18222     c3/return
18223 
18224 test-emit-subx-stmt-select-primitive:
18225     # Select the right primitive between overloads.
18226     #   foo <- increment
18227     # =>
18228     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
18229     #
18230     # There's a variable on the var stack as follows:
18231     #   name: 'foo'
18232     #   type: int
18233     #   register: 'eax'
18234     #
18235     # There's two primitives, as follows:
18236     #   - name: 'increment'
18237     #     out: int/reg
18238     #     value: 'ff 0/subop/increment'
18239     #   - name: 'increment'
18240     #     inout: int/mem
18241     #     value: 'ff 0/subop/increment'
18242     #
18243     # . prologue
18244     55/push-ebp
18245     89/<- %ebp 4/r32/esp
18246     # setup
18247     (clear-stream _test-output-stream)
18248     (clear-stream $_test-output-buffered-file->buffer)
18249 $test-emit-subx-stmt-select-primitive:initialize-type:
18250     # var type/ecx: (payload tree type-id) = int
18251     68/push 0/imm32/right:null
18252     68/push 0/imm32/right:null
18253     68/push 0/imm32/left:unused
18254     68/push 1/imm32/value:int
18255     68/push 1/imm32/is-atom?:true
18256     68/push 0x11/imm32/alloc-id:fake:payload
18257     89/<- %ecx 4/r32/esp
18258 $test-emit-subx-stmt-select-primitive:initialize-var:
18259     # var var-foo/ecx: (payload var)
18260     68/push 0/imm32/register
18261     68/push 0/imm32/register
18262     68/push 0/imm32/no-stack-offset
18263     68/push 1/imm32/block-depth
18264     51/push-ecx
18265     68/push 0x11/imm32/alloc-id:fake
18266     68/push 0/imm32/name
18267     68/push 0/imm32/name
18268     68/push 0x11/imm32/alloc-id:fake:payload
18269     89/<- %ecx 4/r32/esp
18270 $test-emit-subx-stmt-select-primitive:initialize-var-name:
18271     # var-foo->name = "foo"
18272     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
18273     (copy-array Heap "foo" %eax)
18274 $test-emit-subx-stmt-select-primitive:initialize-var-register:
18275     # var-foo->register = "eax"
18276     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
18277     (copy-array Heap "eax" %eax)
18278 $test-emit-subx-stmt-select-primitive:initialize-stmt-var:
18279     # var operand/ebx: (payload stmt-var)
18280     68/push 0/imm32/is-deref:false
18281     68/push 0/imm32/next
18282     68/push 0/imm32/next
18283     51/push-ecx/var-foo
18284     68/push 0x11/imm32/alloc-id:fake
18285     68/push 0x11/imm32/alloc-id:fake:payload
18286     89/<- %ebx 4/r32/esp
18287 $test-emit-subx-stmt-select-primitive:initialize-stmt:
18288     # var stmt/esi: (addr statement)
18289     53/push-ebx/outputs
18290     68/push 0x11/imm32/alloc-id:fake
18291     68/push 0/imm32/no-inouts
18292     68/push 0/imm32/no-inouts
18293     68/push 0/imm32/operation
18294     68/push 0/imm32/operation
18295     68/push 1/imm32
18296     89/<- %esi 4/r32/esp
18297 $test-emit-subx-stmt-select-primitive:initialize-stmt-operation:
18298     # stmt->operation = "increment"
18299     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
18300     (copy-array Heap "increment" %eax)
18301 $test-emit-subx-stmt-select-primitive:initialize-formal-var:
18302     # var formal-var/ebx: (payload var)
18303     68/push 0/imm32/register
18304     68/push 0/imm32/register
18305     68/push 0/imm32/no-stack-offset
18306     68/push 1/imm32/block-depth
18307     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
18308     68/push 0x11/imm32/alloc-id:fake
18309     68/push 0/imm32/name
18310     68/push 0/imm32/name
18311     68/push 0x11/imm32/alloc-id:fake:payload
18312     89/<- %ebx 4/r32/esp
18313 $test-emit-subx-stmt-select-primitive:initialize-formal-var-name:
18314     # formal-var->name = "dummy"
18315     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
18316     (copy-array Heap "dummy" %eax)
18317 $test-emit-subx-stmt-select-primitive:initialize-formal-register:
18318     # formal-var->register = "*"
18319     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
18320     (copy-array Heap "*" %eax)  # Any-register
18321 $test-emit-subx-stmt-select-primitive:initialize-var-list:
18322     # var formal-outputs/ebx: (payload list var)
18323     68/push 0/imm32/next
18324     68/push 0/imm32/next
18325     53/push-ebx/formal-var
18326     68/push 0x11/imm32/alloc-id:fake
18327     68/push 0x11/imm32/alloc-id:fake:payload
18328     89/<- %ebx 4/r32/esp
18329 $test-emit-subx-stmt-select-primitive:initialize-primitive2:
18330     # var primitive2/edi: (payload primitive)
18331     68/push 0/imm32/next
18332     68/push 0/imm32/next
18333     68/push 0/imm32/output-is-write-only
18334     68/push 0/imm32/no-disp32
18335     68/push 0/imm32/no-imm32
18336     68/push 0/imm32/no-r32
18337     68/push 3/imm32/rm32-is-first-output
18338     68/push 0/imm32/subx-name
18339     68/push 0/imm32/subx-name
18340     53/push-ebx/outputs
18341     68/push 0x11/imm32/alloc-id:fake
18342     68/push 0/imm32/no-inouts
18343     68/push 0/imm32/no-inouts
18344     68/push 0/imm32/name
18345     68/push 0/imm32/name
18346     68/push 0x11/imm32/alloc-id:fake:payload
18347     89/<- %edi 4/r32/esp
18348 $test-emit-subx-stmt-select-primitive:initialize-primitive2-name:
18349     # primitives->name = "increment"
18350     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
18351     (copy-array Heap "increment" %eax)
18352 $test-emit-subx-stmt-select-primitive:initialize-primitive2-subx-name:
18353     # primitives->subx-name = "ff 0/subop/increment"
18354     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
18355     (copy-array Heap "ff 0/subop/increment" %eax)
18356 $test-emit-subx-stmt-select-primitive:initialize-primitive:
18357     # var primitives/ebx: (addr primitive)
18358     57/push-edi
18359     68/push 0x11/imm32/alloc-id:fake
18360     68/push 0/imm32/output-is-write-only
18361     68/push 0/imm32/no-disp32
18362     68/push 0/imm32/no-imm32
18363     68/push 0/imm32/no-r32
18364     68/push 1/imm32/rm32-is-first-inout
18365     68/push 0/imm32/subx-name
18366     68/push 0/imm32/subx-name
18367     68/push 0/imm32/no-outputs
18368     68/push 0/imm32/no-outputs
18369     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
18370     68/push 0x11/imm32/alloc-id:fake
18371     68/push 0/imm32/name
18372     68/push 0/imm32/name
18373     89/<- %ebx 4/r32/esp
18374 $test-emit-subx-stmt-select-primitive:initialize-primitive-name:
18375     # primitives->name = "increment"
18376     (copy-array Heap "increment" %ebx)  # Primitive-name
18377 $test-emit-subx-stmt-select-primitive:initialize-primitive-subx-name:
18378     # primitives->subx-name = "ff 0/subop/increment"
18379     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
18380     (copy-array Heap "ff 0/subop/increment" %eax)
18381     # convert
18382     c7 0/subop/copy *Curr-block-depth 0/imm32
18383     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
18384     (flush _test-output-buffered-file)
18385 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
18391     # check output
18392     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive")
18393     # . epilogue
18394     89/<- %esp 5/r32/ebp
18395     5d/pop-to-ebp
18396     c3/return
18397 
18398 test-emit-subx-stmt-select-primitive-2:
18399     # Select the right primitive between overloads.
18400     #   increment foo
18401     # =>
18402     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
18403     #
18404     # There's a variable on the var stack as follows:
18405     #   name: 'foo'
18406     #   type: int
18407     #   register: 'eax'
18408     #
18409     # There's two primitives, as follows:
18410     #   - name: 'increment'
18411     #     out: int/reg
18412     #     value: 'ff 0/subop/increment'
18413     #   - name: 'increment'
18414     #     inout: int/mem
18415     #     value: 'ff 0/subop/increment'
18416     #
18417     # . prologue
18418     55/push-ebp
18419     89/<- %ebp 4/r32/esp
18420     # setup
18421     (clear-stream _test-output-stream)
18422     (clear-stream $_test-output-buffered-file->buffer)
18423 $test-emit-subx-stmt-select-primitive-2:initialize-type:
18424     # var type/ecx: (payload tree type-id) = int
18425     68/push 0/imm32/right:null
18426     68/push 0/imm32/right:null
18427     68/push 0/imm32/left:unused
18428     68/push 1/imm32/value:int
18429     68/push 1/imm32/is-atom?:true
18430     68/push 0x11/imm32/alloc-id:fake:payload
18431     89/<- %ecx 4/r32/esp
18432 $test-emit-subx-stmt-select-primitive-2:initialize-var:
18433     # var var-foo/ecx: (payload var)
18434     68/push 0/imm32/register
18435     68/push 0/imm32/register
18436     68/push 0/imm32/no-stack-offset
18437     68/push 1/imm32/block-depth
18438     51/push-ecx
18439     68/push 0x11/imm32/alloc-id:fake
18440     68/push 0/imm32/name
18441     68/push 0/imm32/name
18442     68/push 0x11/imm32/alloc-id:fake:payload
18443     89/<- %ecx 4/r32/esp
18444 $test-emit-subx-stmt-select-primitive-2:initialize-var-name:
18445     # var-foo->name = "foo"
18446     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
18447     (copy-array Heap "foo" %eax)
18448 $test-emit-subx-stmt-select-primitive-2:initialize-var-register:
18449     # var-foo->register = "eax"
18450     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
18451     (copy-array Heap "eax" %eax)
18452 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-var:
18453     # var operand/ebx: (payload stmt-var)
18454     68/push 0/imm32/is-deref:false
18455     68/push 0/imm32/next
18456     68/push 0/imm32/next
18457     51/push-ecx/var-foo
18458     68/push 0x11/imm32/alloc-id:fake
18459     68/push 0x11/imm32/alloc-id:fake:payload
18460     89/<- %ebx 4/r32/esp
18461 $test-emit-subx-stmt-select-primitive-2:initialize-stmt:
18462     # var stmt/esi: (addr statement)
18463     68/push 0/imm32/no-outputs
18464     68/push 0/imm32/no-outputs
18465     53/push-ebx/inouts
18466     68/push 0x11/imm32/alloc-id:fake
18467     68/push 0/imm32/operation
18468     68/push 0/imm32/operation
18469     68/push 1/imm32
18470     89/<- %esi 4/r32/esp
18471 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-operation:
18472     # stmt->operation = "increment"
18473     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
18474     (copy-array Heap "increment" %eax)
18475 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var:
18476     # var formal-var/ebx: (payload var)
18477     68/push 0/imm32/register
18478     68/push 0/imm32/register
18479     68/push 0/imm32/no-stack-offset
18480     68/push 1/imm32/block-depth
18481     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
18482     68/push 0x11/imm32/alloc-id:fake
18483     68/push 0/imm32/name
18484     68/push 0/imm32/name
18485     68/push 0x11/imm32/alloc-id:fake:payload
18486     89/<- %ebx 4/r32/esp
18487 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var-name:
18488     # formal-var->name = "dummy"
18489     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
18490     (copy-array Heap "dummy" %eax)
18491 $test-emit-subx-stmt-select-primitive-2:initialize-formal-register:
18492     # formal-var->register = "*"
18493     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
18494     (copy-array Heap "*" %eax)  # Any-register
18495 $test-emit-subx-stmt-select-primitive-2:initialize-var-list:
18496     # var formal-outputs/ebx: (payload list stmt-var)
18497     68/push 0/imm32/next
18498     68/push 0/imm32/next
18499     53/push-ebx/formal-var
18500     68/push 0x11/imm32/alloc-id:fake
18501     68/push 0x11/imm32/alloc-id:fake:payload
18502     89/<- %ebx 4/r32/esp
18503 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2:
18504     # var primitive2/edi: (payload primitive)
18505     68/push 0/imm32/next
18506     68/push 0/imm32/next
18507     68/push 0/imm32/output-is-write-only
18508     68/push 0/imm32/no-disp32
18509     68/push 0/imm32/no-imm32
18510     68/push 0/imm32/no-r32
18511     68/push 3/imm32/rm32-is-first-output
18512     68/push 0/imm32/subx-name
18513     68/push 0/imm32/subx-name
18514     53/push-ebx/outputs
18515     68/push 0x11/imm32/alloc-id:fake
18516     68/push 0/imm32/no-inouts
18517     68/push 0/imm32/no-inouts
18518     68/push 0/imm32/name
18519     68/push 0/imm32/name
18520     68/push 0x11/imm32/alloc-id:fake:payload
18521     89/<- %edi 4/r32/esp
18522 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-name:
18523     # primitives->name = "increment"
18524     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
18525     (copy-array Heap "increment" %eax)
18526 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-subx-name:
18527     # primitives->subx-name = "ff 0/subop/increment"
18528     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
18529     (copy-array Heap "ff 0/subop/increment" %eax)
18530 $test-emit-subx-stmt-select-primitive-2:initialize-primitive:
18531     # var primitives/ebx: (addr primitive)
18532     57/push-edi
18533     68/push 0x11/imm32/alloc-id:fake
18534     68/push 0/imm32/output-is-write-only
18535     68/push 0/imm32/no-disp32
18536     68/push 0/imm32/no-imm32
18537     68/push 0/imm32/no-r32
18538     68/push 1/imm32/rm32-is-first-inout
18539     68/push 0/imm32/subx-name
18540     68/push 0/imm32/subx-name
18541     68/push 0/imm32/no-outputs
18542     68/push 0/imm32/no-outputs
18543     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
18544     68/push 0x11/imm32/alloc-id:fake
18545     68/push 0/imm32/name
18546     68/push 0/imm32/name
18547     89/<- %ebx 4/r32/esp
18548 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-name:
18549     # primitives->name = "increment"
18550     (copy-array Heap "increment" %ebx)  # Primitive-name
18551 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-subx-name:
18552     # primitives->subx-name = "ff 0/subop/increment"
18553     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
18554     (copy-array Heap "ff 0/subop/increment" %eax)
18555     # convert
18556     c7 0/subop/copy *Curr-block-depth 0/imm32
18557     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
18558     (flush _test-output-buffered-file)
18559 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
18565     # check output
18566     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive-2")
18567     # . epilogue
18568     89/<- %esp 5/r32/ebp
18569     5d/pop-to-ebp
18570     c3/return
18571 
18572 test-increment-register:
18573     # Select the right register between overloads.
18574     #   foo <- increment
18575     # =>
18576     #   50/increment-eax
18577     #
18578     # There's a variable on the var stack as follows:
18579     #   name: 'foo'
18580     #   type: int
18581     #   register: 'eax'
18582     #
18583     # Primitives are the global definitions.
18584     #
18585     # . prologue
18586     55/push-ebp
18587     89/<- %ebp 4/r32/esp
18588     # setup
18589     (clear-stream _test-output-stream)
18590     (clear-stream $_test-output-buffered-file->buffer)
18591 $test-increment-register:initialize-type:
18592     # var type/ecx: (payload tree type-id) = int
18593     68/push 0/imm32/right:null
18594     68/push 0/imm32/right:null
18595     68/push 0/imm32/left:unused
18596     68/push 1/imm32/value:int
18597     68/push 1/imm32/is-atom?:true
18598     68/push 0x11/imm32/alloc-id:fake:payload
18599     89/<- %ecx 4/r32/esp
18600 $test-increment-register:initialize-var:
18601     # var var-foo/ecx: (payload var)
18602     68/push 0/imm32/register
18603     68/push 0/imm32/register
18604     68/push 0/imm32/no-stack-offset
18605     68/push 1/imm32/block-depth
18606     51/push-ecx
18607     68/push 0x11/imm32/alloc-id:fake
18608     68/push 0/imm32/name
18609     68/push 0/imm32/name
18610     68/push 0x11/imm32/alloc-id:fake:payload
18611     89/<- %ecx 4/r32/esp
18612 $test-increment-register:initialize-var-name:
18613     # var-foo->name = "foo"
18614     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
18615     (copy-array Heap "foo" %eax)
18616 $test-increment-register:initialize-var-register:
18617     # var-foo->register = "eax"
18618     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
18619     (copy-array Heap "eax" %eax)
18620 $test-increment-register:initialize-stmt-var:
18621     # var operand/ebx: (payload stmt-var)
18622     68/push 0/imm32/is-deref:false
18623     68/push 0/imm32/next
18624     68/push 0/imm32/next
18625     51/push-ecx/var-foo
18626     68/push 0x11/imm32/alloc-id:fake
18627     68/push 0x11/imm32/alloc-id:fake:payload
18628     89/<- %ebx 4/r32/esp
18629 $test-increment-register:initialize-stmt:
18630     # var stmt/esi: (addr statement)
18631     53/push-ebx/outputs
18632     68/push 0x11/imm32/alloc-id:fake
18633     68/push 0/imm32/no-inouts
18634     68/push 0/imm32/no-inouts
18635     68/push 0/imm32/operation
18636     68/push 0/imm32/operation
18637     68/push 1/imm32
18638     89/<- %esi 4/r32/esp
18639 $test-increment-register:initialize-stmt-operation:
18640     # stmt->operation = "increment"
18641     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
18642     (copy-array Heap "increment" %eax)
18643     # convert
18644     c7 0/subop/copy *Curr-block-depth 0/imm32
18645     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
18646     (flush _test-output-buffered-file)
18647 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
18653     # check output
18654     (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register")
18655     # . epilogue
18656     89/<- %esp 5/r32/ebp
18657     5d/pop-to-ebp
18658     c3/return
18659 
18660 test-add-reg-to-reg:
18661     #   var1/reg <- add var2/reg
18662     # =>
18663     #   01/add-to %var1 var2
18664     #
18665     # . prologue
18666     55/push-ebp
18667     89/<- %ebp 4/r32/esp
18668     # setup
18669     (clear-stream _test-output-stream)
18670     (clear-stream $_test-output-buffered-file->buffer)
18671 $test-add-reg-to-reg:initialize-type:
18672     # var type/ecx: (payload tree type-id) = int
18673     68/push 0/imm32/right:null
18674     68/push 0/imm32/right:null
18675     68/push 0/imm32/left:unused
18676     68/push 1/imm32/value:int
18677     68/push 1/imm32/is-atom?:true
18678     68/push 0x11/imm32/alloc-id:fake:payload
18679     89/<- %ecx 4/r32/esp
18680 $test-add-reg-to-reg:initialize-var1:
18681     # var var1/ecx: (payload var)
18682     68/push 0/imm32/register
18683     68/push 0/imm32/register
18684     68/push 0/imm32/no-stack-offset
18685     68/push 1/imm32/block-depth
18686     51/push-ecx
18687     68/push 0x11/imm32/alloc-id:fake
18688     68/push 0/imm32/name
18689     68/push 0/imm32/name
18690     68/push 0x11/imm32/alloc-id:fake:payload
18691     89/<- %ecx 4/r32/esp
18692 $test-add-reg-to-reg:initialize-var1-name:
18693     # var1->name = "var1"
18694     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
18695     (copy-array Heap "var1" %eax)
18696 $test-add-reg-to-reg:initialize-var1-register:
18697     # var1->register = "eax"
18698     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
18699     (copy-array Heap "eax" %eax)
18700 $test-add-reg-to-reg:initialize-var2:
18701     # var var2/edx: (payload var)
18702     68/push 0/imm32/register
18703     68/push 0/imm32/register
18704     68/push 0/imm32/no-stack-offset
18705     68/push 1/imm32/block-depth
18706     ff 6/subop/push *(ecx+0x10)
18707     68/push 0x11/imm32/alloc-id:fake
18708     68/push 0/imm32/name
18709     68/push 0/imm32/name
18710     68/push 0x11/imm32/alloc-id:fake:payload
18711     89/<- %edx 4/r32/esp
18712 $test-add-reg-to-reg:initialize-var2-name:
18713     # var2->name = "var2"
18714     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
18715     (copy-array Heap "var2" %eax)
18716 $test-add-reg-to-reg:initialize-var2-register:
18717     # var2->register = "ecx"
18718     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
18719     (copy-array Heap "ecx" %eax)
18720 $test-add-reg-to-reg:initialize-inouts:
18721     # var inouts/esi: (payload stmt-var) = [var2]
18722     68/push 0/imm32/is-deref:false
18723     68/push 0/imm32/next
18724     68/push 0/imm32/next
18725     52/push-edx/var2
18726     68/push 0x11/imm32/alloc-id:fake
18727     68/push 0x11/imm32/alloc-id:fake:payload
18728     89/<- %esi 4/r32/esp
18729 $test-add-reg-to-reg:initialize-outputs:
18730     # var outputs/edi: (payload stmt-var) = [var1]
18731     68/push 0/imm32/is-deref:false
18732     68/push 0/imm32/next
18733     68/push 0/imm32/next
18734     51/push-ecx/var1
18735     68/push 0x11/imm32/alloc-id:fake
18736     68/push 0x11/imm32/alloc-id:fake:payload
18737     89/<- %edi 4/r32/esp
18738 $test-add-reg-to-reg:initialize-stmt:
18739     # var stmt/esi: (addr statement)
18740     68/push 0/imm32/next
18741     68/push 0/imm32/next
18742     57/push-edi/outputs
18743     68/push 0x11/imm32/alloc-id:fake
18744     56/push-esi/inouts
18745     68/push 0x11/imm32/alloc-id:fake
18746     68/push 0/imm32/operation
18747     68/push 0/imm32/operation
18748     68/push 1/imm32/tag:stmt1
18749     89/<- %esi 4/r32/esp
18750 $test-add-reg-to-reg:initialize-stmt-operation:
18751     # stmt->operation = "add"
18752     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
18753     (copy-array Heap "add" %eax)
18754     # convert
18755     c7 0/subop/copy *Curr-block-depth 0/imm32
18756     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
18757     (flush _test-output-buffered-file)
18758 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
18764     # check output
18765     (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg")
18766     # . epilogue
18767     89/<- %esp 5/r32/ebp
18768     5d/pop-to-ebp
18769     c3/return
18770 
18771 test-add-reg-to-mem:
18772     #   add-to var1 var2/reg
18773     # =>
18774     #   01/add-to *(ebp+__) var2
18775     #
18776     # . prologue
18777     55/push-ebp
18778     89/<- %ebp 4/r32/esp
18779     # setup
18780     (clear-stream _test-output-stream)
18781     (clear-stream $_test-output-buffered-file->buffer)
18782 $test-add-reg-to-mem:initialize-type:
18783     # var type/ecx: (payload tree type-id) = int
18784     68/push 0/imm32/right:null
18785     68/push 0/imm32/right:null
18786     68/push 0/imm32/left:unused
18787     68/push 1/imm32/value:int
18788     68/push 1/imm32/is-atom?:true
18789     68/push 0x11/imm32/alloc-id:fake:payload
18790     89/<- %ecx 4/r32/esp
18791 $test-add-reg-to-mem:initialize-var1:
18792     # var var1/ecx: (payload var)
18793     68/push 0/imm32/register
18794     68/push 0/imm32/register
18795     68/push 8/imm32/stack-offset
18796     68/push 1/imm32/block-depth
18797     51/push-ecx
18798     68/push 0x11/imm32/alloc-id:fake
18799     68/push 0/imm32/name
18800     68/push 0/imm32/name
18801     68/push 0x11/imm32/alloc-id:fake:payload
18802     89/<- %ecx 4/r32/esp
18803 $test-add-reg-to-mem:initialize-var1-name:
18804     # var1->name = "var1"
18805     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
18806     (copy-array Heap "var1" %eax)
18807 $test-add-reg-to-mem:initialize-var2:
18808     # var var2/edx: (payload var)
18809     68/push 0/imm32/register
18810     68/push 0/imm32/register
18811     68/push 0/imm32/no-stack-offset
18812     68/push 1/imm32/block-depth
18813     ff 6/subop/push *(ecx+0x10)
18814     68/push 0x11/imm32/alloc-id:fake
18815     68/push 0/imm32/name
18816     68/push 0/imm32/name
18817     68/push 0x11/imm32/alloc-id:fake:payload
18818     89/<- %edx 4/r32/esp
18819 $test-add-reg-to-mem:initialize-var2-name:
18820     # var2->name = "var2"
18821     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
18822     (copy-array Heap "var2" %eax)
18823 $test-add-reg-to-mem:initialize-var2-register:
18824     # var2->register = "ecx"
18825     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
18826     (copy-array Heap "ecx" %eax)
18827 $test-add-reg-to-mem:initialize-inouts:
18828     # var inouts/esi: (payload stmt-var) = [var2]
18829     68/push 0/imm32/is-deref:false
18830     68/push 0/imm32/next
18831     68/push 0/imm32/next
18832     52/push-edx/var2
18833     68/push 0x11/imm32/alloc-id:fake
18834     68/push 0x11/imm32/alloc-id:fake:payload
18835     89/<- %esi 4/r32/esp
18836     # inouts = [var1, var2]
18837     68/push 0/imm32/is-deref:false
18838     56/push-esi/next
18839     68/push 0x11/imm32/alloc-id:fake
18840     51/push-ecx/var1
18841     68/push 0x11/imm32/alloc-id:fake
18842     68/push 0x11/imm32/alloc-id:fake:payload
18843     89/<- %esi 4/r32/esp
18844 $test-add-reg-to-mem:initialize-stmt:
18845     # var stmt/esi: (addr statement)
18846     68/push 0/imm32/next
18847     68/push 0/imm32/next
18848     68/push 0/imm32/outputs
18849     68/push 0/imm32/outputs
18850     56/push-esi/inouts
18851     68/push 0x11/imm32/alloc-id:fake
18852     68/push 0/imm32/operation
18853     68/push 0/imm32/operation
18854     68/push 1/imm32/tag:stmt1
18855     89/<- %esi 4/r32/esp
18856 $test-add-reg-to-mem:initialize-stmt-operation:
18857     # stmt->operation = "add-to"
18858     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
18859     (copy-array Heap "add-to" %eax)
18860     # convert
18861     c7 0/subop/copy *Curr-block-depth 0/imm32
18862     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
18863     (flush _test-output-buffered-file)
18864 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
18870     # check output
18871     (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem")
18872     # . epilogue
18873     89/<- %esp 5/r32/ebp
18874     5d/pop-to-ebp
18875     c3/return
18876 
18877 test-add-mem-to-reg:
18878     #   var1/reg <- add var2
18879     # =>
18880     #   03/add *(ebp+__) var1
18881     #
18882     # . prologue
18883     55/push-ebp
18884     89/<- %ebp 4/r32/esp
18885     # setup
18886     (clear-stream _test-output-stream)
18887     (clear-stream $_test-output-buffered-file->buffer)
18888 $test-add-mem-to-reg:initialize-type:
18889     # var type/ecx: (payload tree type-id) = int
18890     68/push 0/imm32/right:null
18891     68/push 0/imm32/right:null
18892     68/push 0/imm32/left:unused
18893     68/push 1/imm32/value:int
18894     68/push 1/imm32/is-atom?:true
18895     68/push 0x11/imm32/alloc-id:fake:payload
18896     89/<- %ecx 4/r32/esp
18897 $test-add-mem-to-reg:initialize-var:
18898     # var var1/ecx: (payload var)
18899     68/push 0/imm32/register
18900     68/push 0/imm32/register
18901     68/push 0/imm32/no-stack-offset
18902     68/push 1/imm32/block-depth
18903     51/push-ecx
18904     68/push 0x11/imm32/alloc-id:fake
18905     68/push 0/imm32/name
18906     68/push 0/imm32/name
18907     68/push 0x11/imm32/alloc-id:fake:payload
18908     89/<- %ecx 4/r32/esp
18909 $test-add-mem-to-reg:initialize-var-name:
18910     # var1->name = "foo"
18911     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
18912     (copy-array Heap "var1" %eax)
18913 $test-add-mem-to-reg:initialize-var-register:
18914     # var1->register = "eax"
18915     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
18916     (copy-array Heap "eax" %eax)
18917 $test-add-mem-to-reg:initialize-var2:
18918     # var var2/edx: (payload var)
18919     68/push 0/imm32/register
18920     68/push 0/imm32/register
18921     68/push 8/imm32/stack-offset
18922     68/push 1/imm32/block-depth
18923     ff 6/subop/push *(ecx+0x10)
18924     68/push 0x11/imm32/alloc-id:fake
18925     68/push 0/imm32/name
18926     68/push 0/imm32/name
18927     68/push 0x11/imm32/alloc-id:fake:payload
18928     89/<- %edx 4/r32/esp
18929 $test-add-mem-to-reg:initialize-var2-name:
18930     # var2->name = "var2"
18931     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
18932     (copy-array Heap "var2" %eax)
18933 $test-add-mem-to-reg:initialize-inouts:
18934     # var inouts/esi: (payload stmt-var) = [var2]
18935     68/push 0/imm32/is-deref:false
18936     68/push 0/imm32/next
18937     68/push 0/imm32/next
18938     52/push-edx/var2
18939     68/push 0x11/imm32/alloc-id:fake
18940     68/push 0x11/imm32/alloc-id:fake:payload
18941     89/<- %esi 4/r32/esp
18942 $test-add-mem-to-reg:initialize-outputs:
18943     # var outputs/edi: (payload stmt-var) = [var1]
18944     68/push 0/imm32/is-deref:false
18945     68/push 0/imm32/next
18946     68/push 0/imm32/next
18947     51/push-ecx/var1
18948     68/push 0x11/imm32/alloc-id:fake
18949     68/push 0x11/imm32/alloc-id:fake:payload
18950     89/<- %edi 4/r32/esp
18951 $test-add-mem-to-reg:initialize-stmt:
18952     # var stmt/esi: (addr statement)
18953     68/push 0/imm32/next
18954     68/push 0/imm32/next
18955     57/push-edi/outputs
18956     68/push 0x11/imm32/alloc-id:fake
18957     56/push-esi/inouts
18958     68/push 0x11/imm32/alloc-id:fake
18959     68/push 0/imm32/operation
18960     68/push 0/imm32/operation
18961     68/push 1/imm32/tag:stmt1
18962     89/<- %esi 4/r32/esp
18963 $test-add-mem-to-reg:initialize-stmt-operation:
18964     # stmt->operation = "add"
18965     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
18966     (copy-array Heap "add" %eax)
18967     # convert
18968     c7 0/subop/copy *Curr-block-depth 0/imm32
18969     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
18970     (flush _test-output-buffered-file)
18971 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
18977     # check output
18978     (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg")
18979     # . epilogue
18980     89/<- %esp 5/r32/ebp
18981     5d/pop-to-ebp
18982     c3/return
18983 
18984 test-add-literal-to-eax:
18985     #   var1/eax <- add 0x34
18986     # =>
18987     #   05/add-to-eax 0x34/imm32
18988     #
18989     # . prologue
18990     55/push-ebp
18991     89/<- %ebp 4/r32/esp
18992     # setup
18993     (clear-stream _test-output-stream)
18994     (clear-stream $_test-output-buffered-file->buffer)
18995 $test-add-literal-to-eax:initialize-var-type:
18996     # var type/ecx: (payload tree type-id) = int
18997     68/push 0/imm32/right:null
18998     68/push 0/imm32/right:null
18999     68/push 0/imm32/left:unused
19000     68/push 1/imm32/value:int
19001     68/push 1/imm32/is-atom?:true
19002     68/push 0x11/imm32/alloc-id:fake:payload
19003     89/<- %ecx 4/r32/esp
19004 $test-add-literal-to-eax:initialize-var:
19005     # var v/ecx: (payload var)
19006     68/push 0/imm32/register
19007     68/push 0/imm32/register
19008     68/push 0/imm32/no-stack-offset
19009     68/push 1/imm32/block-depth
19010     51/push-ecx
19011     68/push 0x11/imm32/alloc-id:fake
19012     68/push 0/imm32/name
19013     68/push 0/imm32/name
19014     68/push 0x11/imm32/alloc-id:fake:payload
19015     89/<- %ecx 4/r32/esp
19016 $test-add-literal-to-eax:initialize-var-name:
19017     # v->name = "v"
19018     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
19019     (copy-array Heap "v" %eax)
19020 $test-add-literal-to-eax:initialize-var-register:
19021     # v->register = "eax"
19022     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
19023     (copy-array Heap "eax" %eax)
19024 $test-add-literal-to-eax:initialize-literal-type:
19025     # var type/edx: (payload tree type-id) = literal
19026     68/push 0/imm32/right:null
19027     68/push 0/imm32/right:null
19028     68/push 0/imm32/left:unused
19029     68/push 0/imm32/value:literal
19030     68/push 1/imm32/is-atom?:true
19031     68/push 0x11/imm32/alloc-id:fake:payload
19032     89/<- %edx 4/r32/esp
19033 $test-add-literal-to-eax:initialize-literal:
19034     # var l/edx: (payload var)
19035     68/push 0/imm32/register
19036     68/push 0/imm32/register
19037     68/push 0/imm32/no-stack-offset
19038     68/push 1/imm32/block-depth
19039     52/push-edx
19040     68/push 0x11/imm32/alloc-id:fake
19041     68/push 0/imm32/name
19042     68/push 0/imm32/name
19043     68/push 0x11/imm32/alloc-id:fake:payload
19044     89/<- %edx 4/r32/esp
19045 $test-add-literal-to-eax:initialize-literal-value:
19046     # l->name = "0x34"
19047     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
19048     (copy-array Heap "0x34" %eax)
19049 $test-add-literal-to-eax:initialize-inouts:
19050     # var inouts/esi: (payload stmt-var) = [l]
19051     68/push 0/imm32/is-deref:false
19052     68/push 0/imm32/next
19053     68/push 0/imm32/next
19054     52/push-edx/l
19055     68/push 0x11/imm32/alloc-id:fake
19056     68/push 0x11/imm32/alloc-id:fake:payload
19057     89/<- %esi 4/r32/esp
19058 $test-add-literal-to-eax:initialize-outputs:
19059     # var outputs/edi: (payload stmt-var) = [v]
19060     68/push 0/imm32/is-deref:false
19061     68/push 0/imm32/next
19062     68/push 0/imm32/next
19063     51/push-ecx/v
19064     68/push 0x11/imm32/alloc-id:fake
19065     68/push 0x11/imm32/alloc-id:fake:payload
19066     89/<- %edi 4/r32/esp
19067 $test-add-literal-to-eax:initialize-stmt:
19068     # var stmt/esi: (addr statement)
19069     68/push 0/imm32/next
19070     68/push 0/imm32/next
19071     57/push-edi/outputs
19072     68/push 0x11/imm32/alloc-id:fake
19073     56/push-esi/inouts
19074     68/push 0x11/imm32/alloc-id:fake
19075     68/push 0/imm32/operation
19076     68/push 0/imm32/operation
19077     68/push 1/imm32/tag:stmt1
19078     89/<- %esi 4/r32/esp
19079 $test-add-literal-to-eax:initialize-stmt-operation:
19080     # stmt->operation = "add"
19081     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
19082     (copy-array Heap "add" %eax)
19083     # convert
19084     c7 0/subop/copy *Curr-block-depth 0/imm32
19085     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
19086     (flush _test-output-buffered-file)
19087 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
19093     # check output
19094     (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax")
19095     # . epilogue
19096     89/<- %esp 5/r32/ebp
19097     5d/pop-to-ebp
19098     c3/return
19099 
19100 test-add-literal-to-reg:
19101     #   var1/ecx <- add 0x34
19102     # =>
19103     #   81 0/subop/add %ecx 0x34/imm32
19104     #
19105     # . prologue
19106     55/push-ebp
19107     89/<- %ebp 4/r32/esp
19108     # setup
19109     (clear-stream _test-output-stream)
19110     (clear-stream $_test-output-buffered-file->buffer)
19111 $test-add-literal-to-reg:initialize-var-type:
19112     # var type/ecx: (payload tree type-id) = int
19113     68/push 0/imm32/right:null
19114     68/push 0/imm32/right:null
19115     68/push 0/imm32/left:unused
19116     68/push 1/imm32/value:int
19117     68/push 1/imm32/is-atom?:true
19118     68/push 0x11/imm32/alloc-id:fake:payload
19119     89/<- %ecx 4/r32/esp
19120 $test-add-literal-to-reg:initialize-var:
19121     # var v/ecx: (payload var)
19122     68/push 0/imm32/register
19123     68/push 0/imm32/register
19124     68/push 0/imm32/no-stack-offset
19125     68/push 1/imm32/block-depth
19126     51/push-ecx
19127     68/push 0x11/imm32/alloc-id:fake
19128     68/push 0/imm32/name
19129     68/push 0/imm32/name
19130     68/push 0x11/imm32/alloc-id:fake:payload
19131     89/<- %ecx 4/r32/esp
19132 $test-add-literal-to-reg:initialize-var-name:
19133     # v->name = "v"
19134     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
19135     (copy-array Heap "v" %eax)
19136 $test-add-literal-to-reg:initialize-var-register:
19137     # v->register = "ecx"
19138     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
19139     (copy-array Heap "ecx" %eax)
19140 $test-add-literal-to-reg:initialize-literal-type:
19141     # var type/edx: (payload tree type-id) = literal
19142     68/push 0/imm32/right:null
19143     68/push 0/imm32/right:null
19144     68/push 0/imm32/left:unused
19145     68/push 0/imm32/value:literal
19146     68/push 1/imm32/is-atom?:true
19147     68/push 0x11/imm32/alloc-id:fake:payload
19148     89/<- %edx 4/r32/esp
19149 $test-add-literal-to-reg:initialize-literal:
19150     # var l/edx: (payload var)
19151     68/push 0/imm32/register
19152     68/push 0/imm32/register
19153     68/push 0/imm32/no-stack-offset
19154     68/push 1/imm32/block-depth
19155     52/push-edx
19156     68/push 0x11/imm32/alloc-id:fake
19157     68/push 0/imm32/name
19158     68/push 0/imm32/name
19159     68/push 0x11/imm32/alloc-id:fake:payload
19160     89/<- %edx 4/r32/esp
19161 $test-add-literal-to-reg:initialize-literal-value:
19162     # l->name = "0x34"
19163     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
19164     (copy-array Heap "0x34" %eax)
19165 $test-add-literal-to-reg:initialize-inouts:
19166     # var inouts/esi: (payload stmt-var) = [l]
19167     68/push 0/imm32/is-deref:false
19168     68/push 0/imm32/next
19169     68/push 0/imm32/next
19170     52/push-edx/l
19171     68/push 0x11/imm32/alloc-id:fake
19172     68/push 0x11/imm32/alloc-id:fake:payload
19173     89/<- %esi 4/r32/esp
19174 $test-add-literal-to-reg:initialize-outputs:
19175     # var outputs/edi: (payload stmt-var) = [v]
19176     68/push 0/imm32/is-deref:false
19177     68/push 0/imm32/next
19178     68/push 0/imm32/next
19179     51/push-ecx/v
19180     68/push 0x11/imm32/alloc-id:fake
19181     68/push 0x11/imm32/alloc-id:fake:payload
19182     89/<- %edi 4/r32/esp
19183 $test-add-literal-to-reg:initialize-stmt:
19184     # var stmt/esi: (addr statement)
19185     68/push 0/imm32/next
19186     68/push 0/imm32/next
19187     57/push-edi/outputs
19188     68/push 0x11/imm32/alloc-id:fake
19189     56/push-esi/inouts
19190     68/push 0x11/imm32/alloc-id:fake
19191     68/push 0/imm32/operation
19192     68/push 0/imm32/operation
19193     68/push 1/imm32/tag:stmt1
19194     89/<- %esi 4/r32/esp
19195 $test-add-literal-to-reg:initialize-stmt-operation:
19196     # stmt->operation = "add"
19197     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
19198     (copy-array Heap "add" %eax)
19199     # convert
19200     c7 0/subop/copy *Curr-block-depth 0/imm32
19201     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
19202     (flush _test-output-buffered-file)
19203 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
19209     # check output
19210     (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg")
19211     # . epilogue
19212     89/<- %esp 5/r32/ebp
19213     5d/pop-to-ebp
19214     c3/return
19215 
19216 test-add-literal-to-mem:
19217     #   add-to var1, 0x34
19218     # =>
19219     #   81 0/subop/add %eax 0x34/imm32
19220     #
19221     # . prologue
19222     55/push-ebp
19223     89/<- %ebp 4/r32/esp
19224     # setup
19225     (clear-stream _test-output-stream)
19226     (clear-stream $_test-output-buffered-file->buffer)
19227 $test-add-literal-to-mem:initialize-type:
19228     # var type/ecx: (payload tree type-id) = int
19229     68/push 0/imm32/right:null
19230     68/push 0/imm32/right:null
19231     68/push 0/imm32/left:unused
19232     68/push 1/imm32/value:int
19233     68/push 1/imm32/is-atom?:true
19234     68/push 0x11/imm32/alloc-id:fake:payload
19235     89/<- %ecx 4/r32/esp
19236 $test-add-literal-to-mem:initialize-var1:
19237     # var var1/ecx: (payload var)
19238     68/push 0/imm32/register
19239     68/push 0/imm32/register
19240     68/push 8/imm32/stack-offset
19241     68/push 1/imm32/block-depth
19242     51/push-ecx
19243     68/push 0x11/imm32/alloc-id:fake
19244     68/push 0/imm32/name
19245     68/push 0/imm32/name
19246     68/push 0x11/imm32/alloc-id:fake:payload
19247     89/<- %ecx 4/r32/esp
19248 $test-add-literal-to-mem:initialize-var1-name:
19249     # var1->name = "var1"
19250     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
19251     (copy-array Heap "var1" %eax)
19252 $test-add-literal-to-mem:initialize-literal-type:
19253     # var type/edx: (payload tree type-id) = literal
19254     68/push 0/imm32/right:null
19255     68/push 0/imm32/right:null
19256     68/push 0/imm32/left:unused
19257     68/push 0/imm32/value:literal
19258     68/push 1/imm32/is-atom?:true
19259     68/push 0x11/imm32/alloc-id:fake:payload
19260     89/<- %edx 4/r32/esp
19261 $test-add-literal-to-mem:initialize-literal:
19262     # var l/edx: (payload var)
19263     68/push 0/imm32/register
19264     68/push 0/imm32/register
19265     68/push 0/imm32/no-stack-offset
19266     68/push 1/imm32/block-depth
19267     52/push-edx
19268     68/push 0x11/imm32/alloc-id:fake
19269     68/push 0/imm32/name
19270     68/push 0/imm32/name
19271     68/push 0x11/imm32/alloc-id:fake:payload
19272     89/<- %edx 4/r32/esp
19273 $test-add-literal-to-mem:initialize-literal-value:
19274     # l->name = "0x34"
19275     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
19276     (copy-array Heap "0x34" %eax)
19277 $test-add-literal-to-mem:initialize-inouts:
19278     # var inouts/esi: (payload stmt-var) = [l]
19279     68/push 0/imm32/is-deref:false
19280     68/push 0/imm32/next
19281     68/push 0/imm32/next
19282     52/push-edx/l
19283     68/push 0x11/imm32/alloc-id:fake
19284     68/push 0x11/imm32/alloc-id:fake:payload
19285     89/<- %esi 4/r32/esp
19286     # var inouts = (handle stmt-var) = [var1, var2]
19287     68/push 0/imm32/is-deref:false
19288     56/push-esi/next
19289     68/push 0x11/imm32/alloc-id:fake
19290     51/push-ecx/var1
19291     68/push 0x11/imm32/alloc-id:fake
19292     68/push 0x11/imm32/alloc-id:fake:payload
19293     89/<- %esi 4/r32/esp
19294 $test-add-literal-to-mem:initialize-stmt:
19295     # var stmt/esi: (addr statement)
19296     68/push 0/imm32/next
19297     68/push 0/imm32/next
19298     68/push 0/imm32/outputs
19299     68/push 0/imm32/outputs
19300     56/push-esi/inouts
19301     68/push 0x11/imm32/alloc-id:fake
19302     68/push 0/imm32/operation
19303     68/push 0/imm32/operation
19304     68/push 1/imm32/tag:stmt1
19305     89/<- %esi 4/r32/esp
19306 $test-add-literal-to-mem:initialize-stmt-operation:
19307     # stmt->operation = "add-to"
19308     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
19309     (copy-array Heap "add-to" %eax)
19310     # convert
19311     c7 0/subop/copy *Curr-block-depth 0/imm32
19312     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
19313     (flush _test-output-buffered-file)
19314 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
19320     # check output
19321     (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem")
19322     # . epilogue
19323     89/<- %esp 5/r32/ebp
19324     5d/pop-to-ebp
19325     c3/return
19326 
19327 test-compare-reg-with-reg:
19328     #   compare var1/ecx, var2/eax
19329     # =>
19330     #   39/compare %ecx 0/r32/eax
19331     #
19332     # . prologue
19333     55/push-ebp
19334     89/<- %ebp 4/r32/esp
19335     # setup
19336     (clear-stream _test-output-stream)
19337     (clear-stream $_test-output-buffered-file->buffer)
19338 $test-compare-reg-with-reg:initialize-type:
19339     # var type/ecx: (payload tree type-id) = int
19340     68/push 0/imm32/right:null
19341     68/push 0/imm32/right:null
19342     68/push 0/imm32/left:unused
19343     68/push 1/imm32/value:int
19344     68/push 1/imm32/is-atom?:true
19345     68/push 0x11/imm32/alloc-id:fake:payload
19346     89/<- %ecx 4/r32/esp
19347 $test-compare-reg-with-reg:initialize-var1:
19348     # var var1/ecx: (payload var)
19349     68/push 0/imm32/register
19350     68/push 0/imm32/register
19351     68/push 0/imm32/no-stack-offset
19352     68/push 1/imm32/block-depth
19353     51/push-ecx
19354     68/push 0x11/imm32/alloc-id:fake
19355     68/push 0/imm32/name
19356     68/push 0/imm32/name
19357     68/push 0x11/imm32/alloc-id:fake:payload
19358     89/<- %ecx 4/r32/esp
19359 $test-compare-reg-with-reg:initialize-var1-name:
19360     # var1->name = "var1"
19361     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
19362     (copy-array Heap "var1" %eax)
19363 $test-compare-reg-with-reg:initialize-var1-register:
19364     # var1->register = "ecx"
19365     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
19366     (copy-array Heap "ecx" %eax)
19367 $test-compare-reg-with-reg:initialize-var2:
19368     # var var2/edx: (payload var)
19369     68/push 0/imm32/register
19370     68/push 0/imm32/register
19371     68/push 0/imm32/no-stack-offset
19372     68/push 1/imm32/block-depth
19373     ff 6/subop/push *(ecx+0x10)
19374     68/push 0x11/imm32/alloc-id:fake
19375     68/push 0/imm32/name
19376     68/push 0/imm32/name
19377     68/push 0x11/imm32/alloc-id:fake:payload
19378     89/<- %edx 4/r32/esp
19379 $test-compare-reg-with-reg:initialize-var2-name:
19380     # var2->name = "var2"
19381     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
19382     (copy-array Heap "var2" %eax)
19383 $test-compare-reg-with-reg:initialize-var2-register:
19384     # var2->register = "eax"
19385     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
19386     (copy-array Heap "eax" %eax)
19387 $test-compare-reg-with-reg:initialize-inouts:
19388     # var inouts/esi: (payload stmt-var) = [var2]
19389     68/push 0/imm32/is-deref:false
19390     68/push 0/imm32/next
19391     68/push 0/imm32/next
19392     52/push-edx/var2
19393     68/push 0x11/imm32/alloc-id:fake
19394     68/push 0x11/imm32/alloc-id:fake:payload
19395     89/<- %esi 4/r32/esp
19396     # inouts = [var1, var2]
19397     68/push 0/imm32/is-deref:false
19398     56/push-esi/next
19399     68/push 0x11/imm32/alloc-id:fake
19400     51/push-ecx/var1
19401     68/push 0x11/imm32/alloc-id:fake
19402     68/push 0x11/imm32/alloc-id:fake:payload
19403     89/<- %esi 4/r32/esp
19404 $test-compare-reg-with-reg:initialize-stmt:
19405     # var stmt/esi: (addr statement)
19406     68/push 0/imm32/next
19407     68/push 0/imm32/next
19408     68/push 0/imm32/outputs
19409     68/push 0/imm32/outputs
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-compare-reg-with-reg:initialize-stmt-operation:
19417     # stmt->operation = "compare"
19418     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
19419     (copy-array Heap "compare" %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 "39/compare-> %ecx 0x00000000/r32" "F - test-compare-reg-with-reg")
19432     # . epilogue
19433     89/<- %esp 5/r32/ebp
19434     5d/pop-to-ebp
19435     c3/return
19436 
19437 test-compare-mem-with-reg:
19438     #   compare var1, var2/eax
19439     # =>
19440     #   39/compare *(ebp+___) 0/r32/eax
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-compare-mem-with-reg:initialize-type:
19449     # var type/ecx: (payload tree type-id) = 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-compare-mem-with-reg:initialize-var1:
19458     # var var1/ecx: (payload var)
19459     68/push 0/imm32/register
19460     68/push 0/imm32/register
19461     68/push 8/imm32/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-compare-mem-with-reg:initialize-var1-name:
19470     # var1->name = "var1"
19471     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
19472     (copy-array Heap "var1" %eax)
19473 $test-compare-mem-with-reg:initialize-var2:
19474     # var var2/edx: (payload var)
19475     68/push 0/imm32/register
19476     68/push 0/imm32/register
19477     68/push 0/imm32/no-stack-offset
19478     68/push 1/imm32/block-depth
19479     ff 6/subop/push *(ecx+0x10)
19480     68/push 0x11/imm32/alloc-id:fake
19481     68/push 0/imm32/name
19482     68/push 0/imm32/name
19483     68/push 0x11/imm32/alloc-id:fake:payload
19484     89/<- %edx 4/r32/esp
19485 $test-compare-mem-with-reg:initialize-var2-name:
19486     # var2->name = "var2"
19487     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
19488     (copy-array Heap "var2" %eax)
19489 $test-compare-mem-with-reg:initialize-var2-register:
19490     # var2->register = "eax"
19491     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
19492     (copy-array Heap "eax" %eax)
19493 $test-compare-mem-with-reg:initialize-inouts:
19494     # var inouts/esi: (payload stmt-var) = [var2]
19495     68/push 0/imm32/is-deref:false
19496     68/push 0/imm32/next
19497     68/push 0/imm32/next
19498     52/push-edx/var2
19499     68/push 0x11/imm32/alloc-id:fake
19500     68/push 0x11/imm32/alloc-id:fake:payload
19501     89/<- %esi 4/r32/esp
19502     # inouts = [var1, var2]
19503     68/push 0/imm32/is-deref:false
19504     56/push-esi/next
19505     68/push 0x11/imm32/alloc-id:fake
19506     51/push-ecx/var1
19507     68/push 0x11/imm32/alloc-id:fake
19508     68/push 0x11/imm32/alloc-id:fake:payload
19509     89/<- %esi 4/r32/esp
19510 $test-compare-mem-with-reg:initialize-stmt:
19511     # var stmt/esi: (addr statement)
19512     68/push 0/imm32/next
19513     68/push 0/imm32/next
19514     68/push 0/imm32/outputs
19515     68/push 0/imm32/outputs
19516     56/push-esi/inouts
19517     68/push 0x11/imm32/alloc-id:fake
19518     68/push 0/imm32/operation
19519     68/push 0/imm32/operation
19520     68/push 1/imm32/tag:stmt1
19521     89/<- %esi 4/r32/esp
19522 $test-compare-mem-with-reg:initialize-stmt-operation:
19523     # stmt->operation = "compare"
19524     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
19525     (copy-array Heap "compare" %eax)
19526     # convert
19527     c7 0/subop/copy *Curr-block-depth 0/imm32
19528     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
19529     (flush _test-output-buffered-file)
19530 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
19536     # check output
19537     (check-next-stream-line-equal _test-output-stream "39/compare-> *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-mem-with-reg")
19538     # . epilogue
19539     89/<- %esp 5/r32/ebp
19540     5d/pop-to-ebp
19541     c3/return
19542 
19543 test-compare-reg-with-mem:
19544     #   compare var1/eax, var2
19545     # =>
19546     #   3b/compare<- *(ebp+___) 0/r32/eax
19547     #
19548     # . prologue
19549     55/push-ebp
19550     89/<- %ebp 4/r32/esp
19551     # setup
19552     (clear-stream _test-output-stream)
19553     (clear-stream $_test-output-buffered-file->buffer)
19554 $test-compare-reg-with-mem:initialize-type:
19555     # var type/ecx: (payload tree type-id) = int
19556     68/push 0/imm32/right:null
19557     68/push 0/imm32/right:null
19558     68/push 0/imm32/left:unused
19559     68/push 1/imm32/value:int
19560     68/push 1/imm32/is-atom?:true
19561     68/push 0x11/imm32/alloc-id:fake:payload
19562     89/<- %ecx 4/r32/esp
19563 $test-compare-reg-with-mem:initialize-var1:
19564     # var var1/ecx: (payload var)
19565     68/push 0/imm32/register
19566     68/push 0/imm32/register
19567     68/push 0/imm32/no-stack-offset
19568     68/push 1/imm32/block-depth
19569     51/push-ecx
19570     68/push 0x11/imm32/alloc-id:fake
19571     68/push 0/imm32/name
19572     68/push 0/imm32/name
19573     68/push 0x11/imm32/alloc-id:fake:payload
19574     89/<- %ecx 4/r32/esp
19575 $test-compare-reg-with-mem:initialize-var1-name:
19576     # var1->name = "var1"
19577     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
19578     (copy-array Heap "var1" %eax)
19579 $test-compare-reg-with-mem:initialize-var1-register:
19580     # var1->register = "eax"
19581     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
19582     (copy-array Heap "eax" %eax)
19583 $test-compare-reg-with-mem:initialize-var2:
19584     # var var2/edx: (payload var)
19585     68/push 0/imm32/register
19586     68/push 0/imm32/register
19587     68/push 8/imm32/stack-offset
19588     68/push 1/imm32/block-depth
19589     ff 6/subop/push *(ecx+0x10)
19590     68/push 0x11/imm32/alloc-id:fake
19591     68/push 0/imm32/name
19592     68/push 0/imm32/name
19593     68/push 0x11/imm32/alloc-id:fake:payload
19594     89/<- %edx 4/r32/esp
19595 $test-compare-reg-with-mem:initialize-var2-name:
19596     # var2->name = "var2"
19597     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
19598     (copy-array Heap "var2" %eax)
19599 $test-compare-reg-with-mem:initialize-inouts:
19600     # var inouts/esi: (payload stmt-var) = [var2]
19601     68/push 0/imm32/is-deref:false
19602     68/push 0/imm32/next
19603     68/push 0/imm32/next
19604     52/push-edx/var2
19605     68/push 0x11/imm32/alloc-id:fake
19606     68/push 0x11/imm32/alloc-id:fake:payload
19607     89/<- %esi 4/r32/esp
19608     # inouts = [var1, var2]
19609     68/push 0/imm32/is-deref:false
19610     56/push-esi/next
19611     68/push 0x11/imm32/alloc-id:fake
19612     51/push-ecx/var1
19613     68/push 0x11/imm32/alloc-id:fake
19614     68/push 0x11/imm32/alloc-id:fake:payload
19615     89/<- %esi 4/r32/esp
19616 $test-compare-reg-with-mem:initialize-stmt:
19617     # var stmt/esi: (addr statement)
19618     68/push 0/imm32/next
19619     68/push 0/imm32/next
19620     68/push 0/imm32/outputs
19621     68/push 0/imm32/outputs
19622     56/push-esi/inouts
19623     68/push 0x11/imm32/alloc-id:fake
19624     68/push 0/imm32/operation
19625     68/push 0/imm32/operation
19626     68/push 1/imm32/tag:stmt1
19627     89/<- %esi 4/r32/esp
19628 $test-compare-reg-with-mem:initialize-stmt-operation:
19629     # stmt->operation = "compare"
19630     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
19631     (copy-array Heap "compare" %eax)
19632     # convert
19633     c7 0/subop/copy *Curr-block-depth 0/imm32
19634     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
19635     (flush _test-output-buffered-file)
19636 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
19642     # check output
19643     (check-next-stream-line-equal _test-output-stream "3b/compare<- *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-reg-with-mem")
19644     # . epilogue
19645     89/<- %esp 5/r32/ebp
19646     5d/pop-to-ebp
19647     c3/return
19648 
19649 test-compare-mem-with-literal:
19650     #   compare var1, 0x34
19651     # =>
19652     #   81 7/subop/compare *(ebp+___) 0x34/imm32
19653     #
19654     # . prologue
19655     55/push-ebp
19656     89/<- %ebp 4/r32/esp
19657     # setup
19658     (clear-stream _test-output-stream)
19659     (clear-stream $_test-output-buffered-file->buffer)
19660 $test-compare-mem-with-literal:initialize-type:
19661     # var type/ecx: (payload tree type-id) = int
19662     68/push 0/imm32/right:null
19663     68/push 0/imm32/right:null
19664     68/push 0/imm32/left:unused
19665     68/push 1/imm32/value:int
19666     68/push 1/imm32/is-atom?:true
19667     68/push 0x11/imm32/alloc-id:fake:payload
19668     89/<- %ecx 4/r32/esp
19669 $test-compare-mem-with-literal:initialize-var1:
19670     # var var1/ecx: (payload var)
19671     68/push 0/imm32/register
19672     68/push 0/imm32/register
19673     68/push 8/imm32/stack-offset
19674     68/push 1/imm32/block-depth
19675     51/push-ecx
19676     68/push 0x11/imm32/alloc-id:fake
19677     68/push 0/imm32/name
19678     68/push 0/imm32/name
19679     68/push 0x11/imm32/alloc-id:fake:payload
19680     89/<- %ecx 4/r32/esp
19681 $test-compare-mem-with-literal:initialize-var1-name:
19682     # var1->name = "var1"
19683     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
19684     (copy-array Heap "var1" %eax)
19685 $test-compare-mem-with-literal:initialize-literal-type:
19686     # var type/edx: (payload tree type-id) = literal
19687     68/push 0/imm32/right:null
19688     68/push 0/imm32/right:null
19689     68/push 0/imm32/left:unused
19690     68/push 0/imm32/value:literal
19691     68/push 1/imm32/is-atom?:true
19692     68/push 0x11/imm32/alloc-id:fake:payload
19693     89/<- %edx 4/r32/esp
19694 $test-compare-mem-with-literal:initialize-literal:
19695     # var l/edx: (payload var)
19696     68/push 0/imm32/register
19697     68/push 0/imm32/register
19698     68/push 0/imm32/no-stack-offset
19699     68/push 1/imm32/block-depth
19700     52/push-edx
19701     68/push 0x11/imm32/alloc-id:fake
19702     68/push 0/imm32/name
19703     68/push 0/imm32/name
19704     68/push 0x11/imm32/alloc-id:fake:payload
19705     89/<- %edx 4/r32/esp
19706 $test-compare-mem-with-literal:initialize-literal-value:
19707     # l->name = "0x34"
19708     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
19709     (copy-array Heap "0x34" %eax)
19710 $test-compare-mem-with-literal:initialize-inouts:
19711     # var inouts/esi: (payload stmt-var) = [l]
19712     68/push 0/imm32/is-deref:false
19713     68/push 0/imm32/next
19714     68/push 0/imm32/next
19715     52/push-edx/l
19716     68/push 0x11/imm32/alloc-id:fake
19717     68/push 0x11/imm32/alloc-id:fake:payload
19718     89/<- %esi 4/r32/esp
19719     # var inouts = (handle stmt-var) = [var1, var2]
19720     68/push 0/imm32/is-deref:false
19721     56/push-esi/next
19722     68/push 0x11/imm32/alloc-id:fake
19723     51/push-ecx/var1
19724     68/push 0x11/imm32/alloc-id:fake
19725     68/push 0x11/imm32/alloc-id:fake:payload
19726     89/<- %esi 4/r32/esp
19727 $test-compare-mem-with-literal:initialize-stmt:
19728     # var stmt/esi: (addr statement)
19729     68/push 0/imm32/next
19730     68/push 0/imm32/next
19731     68/push 0/imm32/outputs
19732     68/push 0/imm32/outputs
19733     56/push-esi/inouts
19734     68/push 0x11/imm32/alloc-id:fake
19735     68/push 0/imm32/operation
19736     68/push 0/imm32/operation
19737     68/push 1/imm32/tag:stmt1
19738     89/<- %esi 4/r32/esp
19739 $test-compare-mem-with-literal:initialize-stmt-operation:
19740     # stmt->operation = "compare"
19741     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
19742     (copy-array Heap "compare" %eax)
19743     # convert
19744     c7 0/subop/copy *Curr-block-depth 0/imm32
19745     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
19746     (flush _test-output-buffered-file)
19747 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
19753     # check output
19754     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare *(ebp+0x00000008) 0x34/imm32" "F - test-compare-mem-with-literal")
19755     # . epilogue
19756     89/<- %esp 5/r32/ebp
19757     5d/pop-to-ebp
19758     c3/return
19759 
19760 test-compare-eax-with-literal:
19761     #   compare var1/eax 0x34
19762     # =>
19763     #   3d/compare-eax-with 0x34/imm32
19764     #
19765     # . prologue
19766     55/push-ebp
19767     89/<- %ebp 4/r32/esp
19768     # setup
19769     (clear-stream _test-output-stream)
19770     (clear-stream $_test-output-buffered-file->buffer)
19771 $test-compare-eax-with-literal:initialize-type:
19772     # var type/ecx: (payload tree type-id) = int
19773     68/push 0/imm32/right:null
19774     68/push 0/imm32/right:null
19775     68/push 0/imm32/left:unused
19776     68/push 1/imm32/value:int
19777     68/push 1/imm32/is-atom?:true
19778     68/push 0x11/imm32/alloc-id:fake:payload
19779     89/<- %ecx 4/r32/esp
19780 $test-compare-eax-with-literal:initialize-var1:
19781     # var var1/ecx: (payload var)
19782     68/push 0/imm32/register
19783     68/push 0/imm32/register
19784     68/push 0/imm32/no-stack-offset
19785     68/push 1/imm32/block-depth
19786     51/push-ecx
19787     68/push 0x11/imm32/alloc-id:fake
19788     68/push 0/imm32/name
19789     68/push 0/imm32/name
19790     68/push 0x11/imm32/alloc-id:fake:payload
19791     89/<- %ecx 4/r32/esp
19792 $test-compare-eax-with-literal:initialize-var1-name:
19793     # var1->name = "var1"
19794     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
19795     (copy-array Heap "var1" %eax)
19796 $test-compare-eax-with-literal:initialize-var1-register:
19797     # v->register = "eax"
19798     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
19799     (copy-array Heap "eax" %eax)
19800 $test-compare-eax-with-literal:initialize-literal-type:
19801     # var type/edx: (payload tree type-id) = literal
19802     68/push 0/imm32/right:null
19803     68/push 0/imm32/right:null
19804     68/push 0/imm32/left:unused
19805     68/push 0/imm32/value:literal
19806     68/push 1/imm32/is-atom?:true
19807     68/push 0x11/imm32/alloc-id:fake:payload
19808     89/<- %edx 4/r32/esp
19809 $test-compare-eax-with-literal:initialize-literal:
19810     # var l/edx: (payload var)
19811     68/push 0/imm32/register
19812     68/push 0/imm32/register
19813     68/push 0/imm32/no-stack-offset
19814     68/push 1/imm32/block-depth
19815     52/push-edx
19816     68/push 0x11/imm32/alloc-id:fake
19817     68/push 0/imm32/name
19818     68/push 0/imm32/name
19819     68/push 0x11/imm32/alloc-id:fake:payload
19820     89/<- %edx 4/r32/esp
19821 $test-compare-eax-with-literal:initialize-literal-value:
19822     # l->name = "0x34"
19823     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
19824     (copy-array Heap "0x34" %eax)
19825 $test-compare-eax-with-literal:initialize-inouts:
19826     # var inouts/esi: (payload stmt-var) = [l]
19827     68/push 0/imm32/is-deref:false
19828     68/push 0/imm32/next
19829     68/push 0/imm32/next
19830     52/push-edx/l
19831     68/push 0x11/imm32/alloc-id:fake
19832     68/push 0x11/imm32/alloc-id:fake:payload
19833     89/<- %esi 4/r32/esp
19834     # var inouts = (handle stmt-var) = [var1, var2]
19835     68/push 0/imm32/is-deref:false
19836     56/push-esi/next
19837     68/push 0x11/imm32/alloc-id:fake
19838     51/push-ecx/var1
19839     68/push 0x11/imm32/alloc-id:fake
19840     68/push 0x11/imm32/alloc-id:fake:payload
19841     89/<- %esi 4/r32/esp
19842 $test-compare-eax-with-literal:initialize-stmt:
19843     # var stmt/esi: (addr statement)
19844     68/push 0/imm32/next
19845     68/push 0/imm32/next
19846     68/push 0/imm32/outputs
19847     68/push 0/imm32/outputs
19848     56/push-esi/inouts
19849     68/push 0x11/imm32/alloc-id:fake
19850     68/push 0/imm32/operation
19851     68/push 0/imm32/operation
19852     68/push 1/imm32/tag:stmt1
19853     89/<- %esi 4/r32/esp
19854 $test-compare-eax-with-literal:initialize-stmt-operation:
19855     # stmt->operation = "compare"
19856     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
19857     (copy-array Heap "compare" %eax)
19858     # convert
19859     c7 0/subop/copy *Curr-block-depth 0/imm32
19860     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
19861     (flush _test-output-buffered-file)
19862 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
19868     # check output
19869     (check-next-stream-line-equal _test-output-stream "3d/compare-eax-with 0x34/imm32" "F - test-compare-eax-with-literal")
19870     # . epilogue
19871     89/<- %esp 5/r32/ebp
19872     5d/pop-to-ebp
19873     c3/return
19874 
19875 test-compare-reg-with-literal:
19876     #   compare var1/ecx 0x34
19877     # =>
19878     #   81 7/subop/compare %ecx 0x34/imm32
19879     #
19880     # . prologue
19881     55/push-ebp
19882     89/<- %ebp 4/r32/esp
19883     # setup
19884     (clear-stream _test-output-stream)
19885     (clear-stream $_test-output-buffered-file->buffer)
19886 $test-compare-reg-with-literal:initialize-type:
19887     # var type/ecx: (payload tree type-id) = int
19888     68/push 0/imm32/right:null
19889     68/push 0/imm32/right:null
19890     68/push 0/imm32/left:unused
19891     68/push 1/imm32/value:int
19892     68/push 1/imm32/is-atom?:true
19893     68/push 0x11/imm32/alloc-id:fake:payload
19894     89/<- %ecx 4/r32/esp
19895 $test-compare-reg-with-literal:initialize-var1:
19896     # var var1/ecx: (payload var)
19897     68/push 0/imm32/register
19898     68/push 0/imm32/register
19899     68/push 0/imm32/no-stack-offset
19900     68/push 1/imm32/block-depth
19901     51/push-ecx
19902     68/push 0x11/imm32/alloc-id:fake
19903     68/push 0/imm32/name
19904     68/push 0/imm32/name
19905     68/push 0x11/imm32/alloc-id:fake:payload
19906     89/<- %ecx 4/r32/esp
19907 $test-compare-reg-with-literal:initialize-var1-name:
19908     # var1->name = "var1"
19909     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
19910     (copy-array Heap "var1" %eax)
19911 $test-compare-reg-with-literal:initialize-var1-register:
19912     # v->register = "ecx"
19913     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
19914     (copy-array Heap "ecx" %eax)
19915 $test-compare-reg-with-literal:initialize-literal-type:
19916     # var type/edx: (payload tree type-id) = literal
19917     68/push 0/imm32/right:null
19918     68/push 0/imm32/right:null
19919     68/push 0/imm32/left:unused
19920     68/push 0/imm32/value:literal
19921     68/push 1/imm32/is-atom?:true
19922     68/push 0x11/imm32/alloc-id:fake:payload
19923     89/<- %edx 4/r32/esp
19924 $test-compare-reg-with-literal:initialize-literal:
19925     # var l/edx: (payload var)
19926     68/push 0/imm32/register
19927     68/push 0/imm32/register
19928     68/push 0/imm32/no-stack-offset
19929     68/push 1/imm32/block-depth
19930     52/push-edx
19931     68/push 0x11/imm32/alloc-id:fake
19932     68/push 0/imm32/name
19933     68/push 0/imm32/name
19934     68/push 0x11/imm32/alloc-id:fake:payload
19935     89/<- %edx 4/r32/esp
19936 $test-compare-reg-with-literal:initialize-literal-value:
19937     # l->name = "0x34"
19938     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
19939     (copy-array Heap "0x34" %eax)
19940 $test-compare-reg-with-literal:initialize-inouts:
19941     # var inouts/esi: (payload stmt-var) = [l]
19942     68/push 0/imm32/is-deref:false
19943     68/push 0/imm32/next
19944     68/push 0/imm32/next
19945     52/push-edx/l
19946     68/push 0x11/imm32/alloc-id:fake
19947     68/push 0x11/imm32/alloc-id:fake:payload
19948     89/<- %esi 4/r32/esp
19949     # var inouts = (handle stmt-var) = [var1, var2]
19950     68/push 0/imm32/is-deref:false
19951     56/push-esi/next
19952     68/push 0x11/imm32/alloc-id:fake
19953     51/push-ecx/var1
19954     68/push 0x11/imm32/alloc-id:fake
19955     68/push 0x11/imm32/alloc-id:fake:payload
19956     89/<- %esi 4/r32/esp
19957 $test-compare-reg-with-literal:initialize-stmt:
19958     # var stmt/esi: (addr statement)
19959     68/push 0/imm32/next
19960     68/push 0/imm32/next
19961     68/push 0/imm32/outputs
19962     68/push 0/imm32/outputs
19963     56/push-esi/inouts
19964     68/push 0x11/imm32/alloc-id:fake
19965     68/push 0/imm32/operation
19966     68/push 0/imm32/operation
19967     68/push 1/imm32/tag:stmt1
19968     89/<- %esi 4/r32/esp
19969 $test-compare-reg-with-literal:initialize-stmt-operation:
19970     # stmt->operation = "compare"
19971     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
19972     (copy-array Heap "compare" %eax)
19973     # convert
19974     c7 0/subop/copy *Curr-block-depth 0/imm32
19975     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
19976     (flush _test-output-buffered-file)
19977 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
19983     # check output
19984     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare %ecx 0x34/imm32" "F - test-compare-reg-with-literal")
19985     # . epilogue
19986     89/<- %esp 5/r32/ebp
19987     5d/pop-to-ebp
19988     c3/return
19989 
19990 test-emit-subx-stmt-function-call:
19991     # Call a function on a variable on the stack.
19992     #   f foo
19993     # =>
19994     #   (f *(ebp-8))
19995     # (Changing the function name supports overloading in general, but here it
19996     # just serves to help disambiguate things.)
19997     #
19998     # There's a variable on the var stack as follows:
19999     #   name: 'foo'
20000     #   type: int
20001     #   stack-offset: -8
20002     #
20003     # There's nothing in primitives.
20004     #
20005     # We don't perform any checking here on the type of 'f'.
20006     #
20007     # . prologue
20008     55/push-ebp
20009     89/<- %ebp 4/r32/esp
20010     # setup
20011     (clear-stream _test-output-stream)
20012     (clear-stream $_test-output-buffered-file->buffer)
20013 $test-emit-subx-function-call:initialize-type:
20014     # var type/ecx: (payload tree type-id) = int
20015     68/push 0/imm32/right:null
20016     68/push 0/imm32/right:null
20017     68/push 0/imm32/left:unused
20018     68/push 1/imm32/value:int
20019     68/push 1/imm32/is-atom?:true
20020     68/push 0x11/imm32/alloc-id:fake:payload
20021     89/<- %ecx 4/r32/esp
20022 $test-emit-subx-function-call:initialize-var:
20023     # var var-foo/ecx: (payload var) = var(type)
20024     68/push 0/imm32/no-register
20025     68/push 0/imm32/no-register
20026     68/push -8/imm32/stack-offset
20027     68/push 1/imm32/block-depth
20028     51/push-ecx/type
20029     68/push 0x11/imm32/alloc-id:fake
20030     68/push 0/imm32/name
20031     68/push 0/imm32/name
20032     68/push 0x11/imm32/alloc-id:fake:payload
20033     89/<- %ecx 4/r32/esp
20034 $test-emit-subx-function-call:initialize-var-name:
20035     # var-foo->name = "foo"
20036     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20037     (copy-array Heap "foo" %eax)
20038 $test-emit-subx-function-call:initialize-stmt-var:
20039     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
20040     68/push 0/imm32/is-deref:false
20041     68/push 0/imm32/next
20042     68/push 0/imm32/next
20043     51/push-ecx/var-foo
20044     68/push 0x11/imm32/alloc-id:fake
20045     68/push 0x11/imm32/alloc-id:fake:payload
20046     89/<- %ebx 4/r32/esp
20047 $test-emit-subx-function-call:initialize-stmt:
20048     # var stmt/esi: (addr statement)
20049     68/push 0/imm32/no-outputs
20050     68/push 0/imm32/no-outputs
20051     53/push-ebx/inouts
20052     68/push 0x11/imm32/alloc-id:fake
20053     68/push 0/imm32/operation
20054     68/push 0/imm32/operation
20055     68/push 1/imm32/tag
20056     89/<- %esi 4/r32/esp
20057 $test-emit-subx-function-call:initialize-stmt-operation:
20058     # stmt->operation = "f"
20059     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20060     (copy-array Heap "f" %eax)
20061     # convert
20062     c7 0/subop/copy *Curr-block-depth 0/imm32
20063     (emit-subx-stmt _test-output-buffered-file %esi 0 Stderr 0)
20064     (flush _test-output-buffered-file)
20065 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20071     # check output
20072     (check-next-stream-line-equal _test-output-stream "(f *(ebp+0xfffffff8))" "F - test-emit-subx-stmt-function-call")
20073     # . epilogue
20074     89/<- %esp 5/r32/ebp
20075     5d/pop-to-ebp
20076     c3/return
20077 
20078 test-emit-subx-stmt-function-call-with-literal-arg:
20079     # Call a function on a literal.
20080     #   f 0x34
20081     # =>
20082     #   (f2 0x34)
20083     #
20084     # . prologue
20085     55/push-ebp
20086     89/<- %ebp 4/r32/esp
20087     # setup
20088     (clear-stream _test-output-stream)
20089     (clear-stream $_test-output-buffered-file->buffer)
20090 $test-emit-subx-function-call-with-literal-arg:initialize-type:
20091     # var type/ecx: (payload tree type-id) = int
20092     68/push 0/imm32/right:null
20093     68/push 0/imm32/right:null
20094     68/push 0/imm32/left:unused
20095     68/push 0/imm32/value:literal
20096     68/push 1/imm32/is-atom?:true
20097     68/push 0x11/imm32/alloc-id:fake:payload
20098     89/<- %ecx 4/r32/esp
20099 $test-emit-subx-function-call-with-literal-arg:initialize-var:
20100     # var var-foo/ecx: (payload var) = var(lit)
20101     68/push 0/imm32/no-register
20102     68/push 0/imm32/no-register
20103     68/push 0/imm32/no-stack-offset
20104     68/push 1/imm32/block-depth
20105     51/push-ecx/type
20106     68/push 0x11/imm32/alloc-id:fake
20107     68/push 0/imm32/name
20108     68/push 0/imm32/name
20109     68/push 0x11/imm32/alloc-id:fake:payload
20110     89/<- %ecx 4/r32/esp
20111 $test-emit-subx-function-call-with-literal-arg:initialize-var-name:
20112     # var-foo->name = "0x34"
20113     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20114     (copy-array Heap "0x34" %eax)
20115 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-var:
20116     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
20117     68/push 0/imm32/is-deref:false
20118     68/push 0/imm32/next
20119     68/push 0/imm32/next
20120     51/push-ecx/var-foo
20121     68/push 0x11/imm32/alloc-id:fake
20122     68/push 0x11/imm32/alloc-id:fake:payload
20123     89/<- %ebx 4/r32/esp
20124 $test-emit-subx-function-call-with-literal-arg:initialize-stmt:
20125     # var stmt/esi: (addr statement)
20126     68/push 0/imm32/no-outputs
20127     68/push 0/imm32/no-outputs
20128     53/push-ebx/inouts
20129     68/push 0x11/imm32/alloc-id:fake
20130     68/push 0/imm32/operation
20131     68/push 0/imm32/operation
20132     68/push 1/imm32/tag
20133     89/<- %esi 4/r32/esp
20134 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-operation:
20135     # stmt->operation = "f"
20136     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20137     (copy-array Heap "f" %eax)
20138     # convert
20139     c7 0/subop/copy *Curr-block-depth 0/imm32
20140     (emit-subx-stmt _test-output-buffered-file %esi 0 %ebx Stderr 0)
20141     (flush _test-output-buffered-file)
20142 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20148     # check output
20149     (check-next-stream-line-equal _test-output-stream "(f 0x34)" "F - test-emit-subx-stmt-function-call-with-literal-arg")
20150     # . epilogue
20151     89/<- %esp 5/r32/ebp
20152     5d/pop-to-ebp
20153     c3/return
20154 
20155 emit-indent:  # out: (addr buffered-file), n: int
20156     # . prologue
20157     55/push-ebp
20158     89/<- %ebp 4/r32/esp
20159     # . save registers
20160     50/push-eax
20161     # var i/eax: int = n
20162     8b/-> *(ebp+0xc) 0/r32/eax
20163     {
20164       # if (i <= 0) break
20165       3d/compare-eax-with 0/imm32
20166       7e/jump-if-<= break/disp8
20167       (write-buffered *(ebp+8) "  ")
20168       48/decrement-eax
20169       eb/jump loop/disp8
20170     }
20171 $emit-indent:end:
20172     # . restore registers
20173     58/pop-to-eax
20174     # . epilogue
20175     89/<- %esp 5/r32/ebp
20176     5d/pop-to-ebp
20177     c3/return
20178 
20179 emit-subx-prologue:  # out: (addr buffered-file)
20180     # . prologue
20181     55/push-ebp
20182     89/<- %ebp 4/r32/esp
20183     #
20184     (write-buffered *(ebp+8) "  # . prologue\n")
20185     (write-buffered *(ebp+8) "  55/push-ebp\n")
20186     (write-buffered *(ebp+8) "  89/<- %ebp 4/r32/esp\n")
20187 $emit-subx-prologue:end:
20188     # . epilogue
20189     89/<- %esp 5/r32/ebp
20190     5d/pop-to-ebp
20191     c3/return
20192 
20193 emit-subx-epilogue:  # out: (addr buffered-file)
20194     # . prologue
20195     55/push-ebp
20196     89/<- %ebp 4/r32/esp
20197     #
20198     (write-buffered *(ebp+8) "  # . epilogue\n")
20199     (write-buffered *(ebp+8) "  89/<- %esp 5/r32/ebp\n")
20200     (write-buffered *(ebp+8) "  5d/pop-to-ebp\n")
20201     (write-buffered *(ebp+8) "  c3/return\n")
20202 $emit-subx-epilogue:end:
20203     # . epilogue
20204     89/<- %esp 5/r32/ebp
20205     5d/pop-to-ebp
20206     c3/return