make room for a task before fractional numbers
[mu.git] / linux / mu.subx
blob879b751e529d612e44736715e2efe9a53f138f86
1 # The Mu computer's level-2 language, also called Mu.
2 # http://akkartik.name/post/mu-2019-2
4 # To run:
5 #   $ ./translate_subx init.linux [0-9]*.subx mu.subx
6 #   $ ./a.elf < prog.mu > prog.elf
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)
20 # == Language description
21 # A program is a sequence of function and type definitions.
23 # Function example:
24 #   fn foo n: int -> _/eax: int {
25 #     ...
26 #   }
28 # Functions consist of a name, optional inputs, optional outputs and a block.
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.
37 # Function inputs are always passed in memory (on the stack), while outputs
38 # are always returned in registers. Outputs can't be named; they use the
39 # dummy value '_'.
41 # Blocks mostly consist of statements.
43 # Statements mostly consist of a name, optional inputs and optional outputs.
45 # Statement inputs are variables or literals. Variables need to specify type
46 # (and storage) the first time they're mentioned but not later.
48 # Statement outputs, like function outputs, must be variables in registers.
50 # Statement names must be either primitives or user-defined functions.
52 # Primitives can write to any register.
53 # User-defined functions only write to hard-coded registers. Outputs of each
54 # call must have the same registers as in the function definition.
56 # There are some other statement types:
57 #   - blocks. Multiple statements surrounded by '{...}' and optionally
58 #     prefixed with a label name and ':'
59 #       - {
60 #           ...
61 #         }
62 #       - foo: {
63 #           ...
64 #         }
66 #   - variable definitions on the stack. E.g.:
67 #       - var foo: int
68 #       - var bar: (array int 3)
69 #     There's no initializer; variables are automatically initialized.
70 #     The type of a local variable is either word-length (4 bytes) or starts with 'ref'.
72 #   - variables definitions in a register. E.g.:
73 #       - var foo/eax: int <- add bar 1
74 #     The initializer is mandatory and must be a valid instruction that writes
75 #     a single output to the right register. In practice registers will
76 #     usually be either initialized by primitives or copied from eax.
77 #       - var eax: int <- foo bar quux
78 #         var floo/ecx: int <- copy eax
80 # Still todo:
81 #   global variables
82 #   union types
84 # Formal types:
85 #   A program is a linked list of functions
86 #   A function contains:
87 #     name: (handle array byte)
88 #     inouts: linked list of vars  <-- 'inouts' is more precise than 'inputs'
89 #       data: (handle var)
90 #       next: (handle list)
91 #     outputs: linked list of vars
92 #       data: (handle var)
93 #       next: (handle list)
94 #     body: (handle block)
95 #   A var-type contains:
96 #     name: (handle array byte)
97 #     type: (handle type-tree)
99 #   A statement can be:
100 #     tag 0: a block
101 #     tag 1: a simple statement (stmt1)
102 #     tag 2: a variable defined on the stack
103 #     tag 3: a variable defined in a register
105 #   A block contains:
106 #     tag: 0
107 #     statements: (handle list stmt)
108 #     name: (handle array byte) -- starting with '$'
110 #   A regular statement contains:
111 #     tag: 1
112 #     operation: (handle array byte)
113 #     inouts: (handle list operand)
114 #     outputs: (handle list var)
116 #   A variable defined on the stack contains:
117 #     tag: 2
118 #     name: (handle array byte)
119 #     type: (handle type-tree)
121 #   A variable defined in a register contains:
122 #     tag: 3
123 #     name: (handle array byte)
124 #     type: (handle type-tree)
125 #     reg: (handle array byte)
127 # == Translation: managing the stack
128 # Now that we know what the language looks like in the large, let's think
129 # about how translation happens from the bottom up. One crucial piece of the
130 # puzzle is how Mu will clean up variables defined on the stack for you.
132 # Assume that we maintain a 'functions' list while parsing source code. And a
133 # 'primitives' list is a global constant. Both these contain enough information
134 # to perform type-checking on function calls or primitive statements, respectively.
136 # Defining variables pushes them on a stack with the current block depth and
137 # enough information about their location (stack offset or register).
138 # Starting a block increments the current block id.
139 # Each statement now has enough information to emit code for it.
140 # Ending a block is where the magic happens:
141 #   pop all variables at the current block depth
142 #   emit code to restore all register variables introduced at the current depth
143 #   emit code to clean up all stack variables at the current depth (just increment esp)
144 #   decrement the current block depth
146 # Formal types:
147 #   live-vars: stack of vars
148 #   var:
149 #     name: (handle array byte)
150 #     type: (handle type-tree)
151 #     block: int
152 #     stack-offset: int  (added to ebp)
153 #     register: (handle array byte)
154 #       either usual register names
155 #       or '*' to indicate any register
156 #   At most one of stack-offset or register-index must be non-zero.
157 #   A register of '*' designates a variable _template_. Only legal in formal
158 #   parameters for primitives.
160 # == Translating a single function call
161 # This one's easy. Assuming we've already checked things, we just drop the
162 # outputs (which use hard-coded registers) and emit inputs in a standard format.
164 # out1, out2, out3, ... <- name inout1, inout2, inout3, ...
165 # =>
166 # (name inout1 inout2 inout3)
168 # Formal types:
169 #   functions: linked list of info
170 #     name: (handle array byte)
171 #     inouts: linked list of vars
172 #     outputs: linked list of vars
173 #     body: block (linked list of statements)
175 # == Translating a single primitive instruction
176 # A second crucial piece of the puzzle is how Mu converts fairly regular
177 # primitives with their uniform syntax to SubX instructions with their gnarly
178 # x86 details.
180 # Mu instructions have inputs and outputs. Primitives can have up to 2 of
181 # them.
182 # SubX instructions have rm32 and r32 operands.
183 # The translation between them covers almost all the possibilities.
184 #   Instructions with 1 inout may turn into ones with 1 rm32
185 #     (e.g. incrementing a var on the stack)
186 #   Instructions with 1 output may turn into ones with 1 rm32
187 #     (e.g. incrementing a var in a register)
188 #   1 inout and 1 output may turn into 1 rm32 and 1 r32
189 #     (e.g. adding a var to a reg)
190 #   2 inouts may turn into 1 rm32 and 1 r32
191 #     (e.g. adding a reg to a var)
192 #   1 inout and 1 literal may turn into 1 rm32 and 1 imm32
193 #     (e.g. adding a constant to a var)
194 #   1 output and 1 literal may turn into 1 rm32 and 1 imm32
195 #     (e.g. adding a constant to a reg)
196 #   2 outputs to hardcoded registers and 1 inout may turn into 1 rm32
197 #     (special-case: divide edx:eax by a var or reg)
198 # Observations:
199 #   We always emit rm32. It may be the first inout or the first output.
200 #   We may emit r32 or imm32 or neither.
201 #   When we emit r32 it may come from first inout or second inout or first output.
203 # Accordingly, the formal data structure for a primitive looks like this:
204 #   primitives: linked list of info
205 #     name: (handle array byte)
206 #     mu-inouts: linked list of vars to check
207 #     mu-outputs: linked list of vars to check; at most a singleton
208 #     subx-name: (handle array byte)
209 #     subx-rm32: enum arg-location
210 #     subx-r32: enum arg-location
211 #     subx-imm32: enum arg-location
212 #     subx-imm8: enum arg-location
213 #     subx-disp32: enum arg-location
214 #     subx-xm32: enum arg-location
215 #     subx-x32: enum arg-location
216 #   arg-location: enum
217 #     0 means none
218 #     1 means first inout
219 #     2 means second inout
220 #     3 means first output
222 # == Translating a block
223 # Emit block name if necessary
224 # Emit '{'
225 # When you encounter a statement, emit it as above
226 # When you encounter a variable declaration
227 #   emit any code needed for it (bzeros)
228 #   push it on the var stack
229 #   update register dict if necessary
230 # When you encounter '}'
231 #   While popping variables off the var stack until block id changes
232 #     Emit code needed to clean up the stack
233 #       either increment esp
234 #       or pop into appropriate register
236 # The rest is straightforward.
238 == data
240 Program:
241 _Program-functions:  # (handle function)
242   0/imm32
243 _Program-functions->payload:
244   0/imm32
245 _Program-types:  # (handle typeinfo)
246   0/imm32
247 _Program-types->payload:
248   0/imm32
249 _Program-signatures:  # (handle function)
250   0/imm32
251 _Program-signatures->payload:
252   0/imm32
254 # Some constants for simulating the data structures described above.
255 # Many constants here come with a type in a comment.
257 # Sometimes the type is of the value at that offset for the given type. For
258 # example, if you start at a function record and move forward Function-inouts
259 # bytes, you'll find a (handle list var).
261 # At other times, the type is of the constant itself. For example, the type of
262 # the constant Function-size is (addr int). To get the size of a function,
263 # look in *Function-size.
265 Function-name:  # (handle array byte)
266   0/imm32
267 Function-inouts:  # (handle list var)
268   8/imm32
269 Function-outputs:  # (handle list var)
270   0x10/imm32
271 Function-body:  # (handle block)
272   0x18/imm32
273 Function-next:  # (handle function)
274   0x20/imm32
275 Function-size:  # (addr int)
276   0x28/imm32/40
278 Primitive-name:  # (handle array byte)
279   0/imm32
280 Primitive-inouts:  # (handle list var)
281   8/imm32
282 Primitive-outputs:  # (handle list var)
283   0x10/imm32
284 Primitive-subx-name:  # (handle array byte)
285   0x18/imm32
286 Primitive-subx-rm32:  # enum arg-location
287   0x20/imm32
288 Primitive-subx-r32:  # enum arg-location
289   0x24/imm32
290 Primitive-subx-imm32:  # enum arg-location
291   0x28/imm32
292 Primitive-subx-imm8:  # enum arg-location  -- only for bit shifts
293   0x2c/imm32
294 Primitive-subx-disp32:  # enum arg-location  -- only for branches
295   0x30/imm32
296 Primitive-subx-xm32:  # enum arg-location
297   0x34/imm32
298 Primitive-subx-x32:  # enum arg-location
299   0x38/imm32
300 Primitive-next:  # (handle function)
301   0x3c/imm32
302 Primitive-size:  # (addr int)
303   0x44/imm32/68
305 Stmt-tag:  # int
306   0/imm32
308 Block-stmts:  # (handle list stmt)
309   4/imm32
310 Block-var:  # (handle var)
311   0xc/imm32
313 Stmt1-operation:  # (handle array byte)
314   4/imm32
315 Stmt1-inouts:  # (handle stmt-var)
316   0xc/imm32
317 Stmt1-outputs:  # (handle stmt-var)
318   0x14/imm32
320 Vardef-var:  # (handle var)
321   4/imm32
323 Regvardef-operation:  # (handle array byte)
324   4/imm32
325 Regvardef-inouts:  # (handle stmt-var)
326   0xc/imm32
327 Regvardef-outputs:  # (handle stmt-var)  # will have exactly one element
328   0x14/imm32
330 Stmt-size:  # (addr int)
331   0x1c/imm32
333 Var-name:  # (handle array byte)
334   0/imm32
335 Var-type:  # (handle type-tree)
336   8/imm32
337 Var-block-depth:  # int -- not available until code-generation time
338   0x10/imm32
339 Var-offset:  # int -- not available until code-generation time
340   0x14/imm32
341 Var-register:  # (handle array byte) -- name of a register
342   0x18/imm32
343 Var-size:  # (addr int)
344   0x20/imm32
346 List-value:  # (handle _)
347   0/imm32
348 List-next:  # (handle list _)
349   8/imm32
350 List-size:  # (addr int)
351   0x10/imm32
353 # A stmt-var is like a list of vars with call-site specific metadata
354 Stmt-var-value:  # (handle var)
355   0/imm32
356 Stmt-var-next:  # (handle stmt-var)
357   8/imm32
358 Stmt-var-is-deref:  # boolean
359   0x10/imm32
360 Stmt-var-size:  # (addr int)
361   0x14/imm32
363 # A live-var is a var augmented with information needed for tracking live
364 # variables.
365 Live-var-value:  # (handle var)
366   0/imm32
367 Live-var-register-spilled:  # boolean; only used if value is in a register, and only during code-gen
368   8/imm32
369 Live-var-size:  # (addr int)
370   0xc/imm32
372 # Types are expressed as trees (s-expressions) of type-ids (ints).
374 Type-tree-is-atom:  # boolean
375   0/imm32
376 # if is-atom?
377 Type-tree-value:  # type-id
378   4/imm32
379 Type-tree-value-size:  # int (for static data structure sizes)
380   8/imm32
381 Type-tree-parameter-name:  # (handle array byte) for type parameters
382   8/imm32
383 # unless is-atom?
384 Type-tree-left:  # (addr type-tree)
385   4/imm32
386 Type-tree-right:  # (addr type-tree)
387   0xc/imm32
389 Type-tree-size:  # (addr int)
390   0x14/imm32
392 # Types
394 # TODO: Turn this data structure into valid Mu, with (fake) handles rather than addrs.
395 Type-id:  # (stream (addr array byte))
396   0/imm32/write  # initialized later from Primitive-type-ids
397   0/imm32/read
398   0x100/imm32/size
399   # data
400   0/imm32  # 0 reserved for literals; value is just the name
401            # Not to be used directly, so we don't include a name here.
402   "int"/imm32  # 1
403   "addr"/imm32  # 2
404   "array"/imm32  # 3
405   "handle"/imm32  # 4
406   "boolean"/imm32  # 5
407   0/imm32  # 6 reserved for constants; they're like literals, but value is an int in Var-offset
408            # Not to be used directly, so we don't include a name here.
409   "offset"/imm32  # 7: (offset T) is guaranteed to be a 32-bit multiple of size-of(T)
410   # 0x20
411   "byte"/imm32  # 8
412   0/imm32  # 9 reserved for array-capacity; value is in Type-tree-size.
413            # Not to be used directly, so we don't include a name here.
414   0/imm32  # 10 reserved for type parameters; value is (address array byte) in Type-tree-value2.
415            # Not to be used directly, so we don't include a name here.
416   "stream"/imm32  # 11
417   "slice"/imm32  # 12
418   "code-point"/imm32  # 13; smallest scannable unit from a text stream
419   "grapheme"/imm32  # 14; smallest printable unit; will eventually be composed of multiple code-points, but currently corresponds 1:1
420                     # only 4-byte graphemes in utf-8 are currently supported;
421                     # unclear how we should deal with larger clusters.
422   "float"/imm32     # 15
423   # 0x40
424   0/imm32  # 16 reserved for literal strings; value is just the name
425            # Not to be used directly, so we don't include a name here.
426            # TODO: move this up next to literal ints
427   # Keep Primitive-type-ids in sync if you add types here.
428           0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
429   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
430   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
431   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
432   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
433   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
435 Primitive-type-ids:  # (addr int)
436   0x44
438 # == Type definitions
439 # Program->types contains some typeinfo for each type definition.
440 # Types contain vars with types, but can't specify registers.
441 Typeinfo-id:  # type-id
442   0/imm32
443 Typeinfo-fields:  # (handle table (handle array byte) (handle typeinfo-entry))
444   4/imm32
445 # Total size must be >= 0
446 # During parsing it may take on two additional values:
447 #   -2: not yet initialized
448 #   -1: in process of being computed
449 # See populate-mu-type-sizes for details.
450 Typeinfo-total-size-in-bytes:  # int
451   0xc/imm32
452 Typeinfo-next:  # (handle typeinfo)
453   0x10/imm32
454 Typeinfo-size:  # (addr int)
455   0x18/imm32
457 # Each entry in the typeinfo->fields table has a pointer to a string and a
458 # pointer to a typeinfo-entry.
459 Typeinfo-fields-row-size:  # (addr int)
460   0x10/imm32
462 # typeinfo-entry objects have information about a field in a single record type
464 # each field of a type is represented using two var's:
465 #   1. the input var: expected type of the field; convenient for creating using parse-var-with-type
466 #   2. the output var: a constant containing the byte offset; convenient for code-generation
467 # computing the output happens after parsing; in the meantime we preserve the
468 # order of fields in the 'index' field.
469 Typeinfo-entry-input-var:  # (handle var)
470   0/imm32
471 Typeinfo-entry-index:  # int
472   8/imm32
473 Typeinfo-entry-output-var:  # (handle var)
474   0xc/imm32
475 Typeinfo-entry-size:  # (addr int)
476   0x14/imm32
478 == code
480 Entry:
481     # . prologue
482     89/<- %ebp 4/r32/esp
483     (new-segment *Heap-size Heap)
484 #?     (test-address-with-right-type-for-stream)
485     # if (argv[1] == "test') run-tests()
486     {
487       # if (argc <= 1) break
488       81 7/subop/compare *ebp 1/imm32
489       7e/jump-if-<= break/disp8
490       # if (argv[1] != "test") break
491       (kernel-string-equal? *(ebp+8) "test")  # => eax
492       3d/compare-eax-and 0/imm32/false
493       74/jump-if-= break/disp8
494       #
495       (run-tests)
496       # syscall_exit(*Num-test-failures)
497       8b/-> *Num-test-failures 3/r32/ebx
498       eb/jump $mu-main:end/disp8
499     }
500     # otherwise convert Stdin
501     (write-buffered Stdout "== code\n")
502     (convert-mu Stdin Stdout Stderr 0)
503     (flush Stdout)
504     # syscall_exit(0)
505     bb/copy-to-ebx 0/imm32
506 $mu-main:end:
507     e8/call syscall_exit/disp32
509 convert-mu:  # in: (addr buffered-file), out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
510     # . prologue
511     55/push-ebp
512     89/<- %ebp 4/r32/esp
513     # . save registers
514     50/push-eax
515     # initialize global data structures
516     c7 0/subop/copy *Next-block-index 1/imm32
517     8b/-> *Primitive-type-ids 0/r32/eax
518     89/<- *Type-id 0/r32/eax  # stream-write
519     c7 0/subop/copy *_Program-functions 0/imm32
520     c7 0/subop/copy *_Program-functions->payload 0/imm32
521     c7 0/subop/copy *_Program-types 0/imm32
522     c7 0/subop/copy *_Program-types->payload 0/imm32
523     c7 0/subop/copy *_Program-signatures 0/imm32
524     c7 0/subop/copy *_Program-signatures->payload 0/imm32
525     #
526     (parse-mu *(ebp+8) *(ebp+0x10) *(ebp+0x14))
527     (populate-mu-type-sizes *(ebp+0x10) *(ebp+0x14))
528 #?     (dump-typeinfos "=== typeinfos\n")
529     (check-mu-types *(ebp+0x10) *(ebp+0x14))
530     (emit-subx *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
531 $convert-mu:end:
532     # . restore registers
533     58/pop-to-eax
534     # . epilogue
535     89/<- %esp 5/r32/ebp
536     5d/pop-to-ebp
537     c3/return
539 test-convert-empty-input:
540     # empty input => empty output
541     # . prologue
542     55/push-ebp
543     89/<- %ebp 4/r32/esp
544     # setup
545     (clear-stream _test-input-stream)
546     (clear-stream $_test-input-buffered-file->buffer)
547     (clear-stream _test-output-stream)
548     (clear-stream $_test-output-buffered-file->buffer)
549     #
550     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
551     (flush _test-output-buffered-file)
552     (check-stream-equal _test-output-stream "" "F - test-convert-empty-input")
553     # . epilogue
554     89/<- %esp 5/r32/ebp
555     5d/pop-to-ebp
556     c3/return
558 test-convert-function-skeleton:
559     # . prologue
560     55/push-ebp
561     89/<- %ebp 4/r32/esp
562     # setup
563     (clear-stream _test-input-stream)
564     (clear-stream $_test-input-buffered-file->buffer)
565     (clear-stream _test-output-stream)
566     (clear-stream $_test-output-buffered-file->buffer)
567     #
568     (write _test-input-stream "fn foo {\n")
569     (write _test-input-stream "}\n")
570     # convert
571     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
572     (flush _test-output-buffered-file)
573 #?     # dump _test-output-stream {{{
574 #?     (write 2 "^")
575 #?     (write-stream 2 _test-output-stream)
576 #?     (write 2 "$\n")
577 #?     (rewind-stream _test-output-stream)
578 #?     # }}}
579     # check output
580     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-skeleton/0")
581     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-skeleton/1")
582     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-skeleton/2")
583     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-skeleton/3")
584     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-skeleton/4")
585     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-skeleton/5")
586     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-skeleton/6")
587     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-skeleton/7")
588     # . epilogue
589     89/<- %esp 5/r32/ebp
590     5d/pop-to-ebp
591     c3/return
593 test-convert-multiple-function-skeletons:
594     # . prologue
595     55/push-ebp
596     89/<- %ebp 4/r32/esp
597     # setup
598     (clear-stream _test-input-stream)
599     (clear-stream $_test-input-buffered-file->buffer)
600     (clear-stream _test-output-stream)
601     (clear-stream $_test-output-buffered-file->buffer)
602     #
603     (write _test-input-stream "fn foo {\n")
604     (write _test-input-stream "}\n")
605     (write _test-input-stream "fn bar {\n")
606     (write _test-input-stream "}\n")
607     # convert
608     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
609     (flush _test-output-buffered-file)
610 #?     # dump _test-output-stream {{{
611 #?     (write 2 "^")
612 #?     (write-stream 2 _test-output-stream)
613 #?     (write 2 "$\n")
614 #?     (rewind-stream _test-output-stream)
615 #?     # }}}
616     # check first function
617     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-multiple-function-skeletons/0")
618     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/1")
619     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/2")
620     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/3")
621     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/4")
622     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/5")
623     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/6")
624     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/7")
625     # check second function
626     (check-next-stream-line-equal _test-output-stream "bar:"                    "F - test-convert-multiple-function-skeletons/10")
627     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/11")
628     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/12")
629     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/13")
630     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/14")
631     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/15")
632     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/16")
633     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/17")
634     # . epilogue
635     89/<- %esp 5/r32/ebp
636     5d/pop-to-ebp
637     c3/return
639 test-convert-function-with-arg:
640     # . prologue
641     55/push-ebp
642     89/<- %ebp 4/r32/esp
643     # setup
644     (clear-stream _test-input-stream)
645     (clear-stream $_test-input-buffered-file->buffer)
646     (clear-stream _test-output-stream)
647     (clear-stream $_test-output-buffered-file->buffer)
648     #
649     (write _test-input-stream "fn foo n: int {\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 #?     # dump _test-output-stream {{{
655 #?     (write 2 "^")
656 #?     (write-stream 2 _test-output-stream)
657 #?     (write 2 "$\n")
658 #?     (rewind-stream _test-output-stream)
659 #?     # }}}
660     # check output
661     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg/0")
662     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg/1")
663     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg/2")
664     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg/3")
665     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg/4")
666     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg/5")
667     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg/6")
668     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg/7")
669     # . epilogue
670     89/<- %esp 5/r32/ebp
671     5d/pop-to-ebp
672     c3/return
674 test-function-with-redefined-name:
675     # . prologue
676     55/push-ebp
677     89/<- %ebp 4/r32/esp
678     # setup
679     (clear-stream _test-input-stream)
680     (clear-stream $_test-input-buffered-file->buffer)
681     (clear-stream _test-output-stream)
682     (clear-stream $_test-output-buffered-file->buffer)
683     (clear-stream _test-error-stream)
684     (clear-stream $_test-error-buffered-file->buffer)
685     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
686     68/push 0/imm32
687     68/push 0/imm32
688     89/<- %edx 4/r32/esp
689     (tailor-exit-descriptor %edx 0x10)
690     #
691     (write _test-input-stream "fn foo {\n")
692     (write _test-input-stream "}\n")
693     (write _test-input-stream "fn foo {\n")
694     (write _test-input-stream "}\n")
695     # convert
696     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
697     # registers except esp clobbered at this point
698     # restore ed
699     89/<- %edx 4/r32/esp
700     (flush _test-output-buffered-file)
701     (flush _test-error-buffered-file)
702 #?     # dump _test-error-stream {{{
703 #?     (write 2 "^")
704 #?     (write-stream 2 _test-error-stream)
705 #?     (write 2 "$\n")
706 #?     (rewind-stream _test-error-stream)
707 #?     # }}}
708     # check output
709     (check-stream-equal _test-output-stream  ""  "F - test-function-with-redefined-name: output should be empty")
710     (check-next-stream-line-equal _test-error-stream  "fn foo defined more than once"  "F - test-function-with-redefined-name: error message")
711     # check that stop(1) was called
712     (check-ints-equal *(edx+4) 2 "F - test-function-with-redefined-name: exit status")
713     # don't restore from ebp
714     81 0/subop/add %esp 8/imm32
715     # . epilogue
716     5d/pop-to-ebp
717     c3/return
719 test-function-with-redefined-name-2:
720     # . prologue
721     55/push-ebp
722     89/<- %ebp 4/r32/esp
723     # setup
724     (clear-stream _test-input-stream)
725     (clear-stream $_test-input-buffered-file->buffer)
726     (clear-stream _test-output-stream)
727     (clear-stream $_test-output-buffered-file->buffer)
728     (clear-stream _test-error-stream)
729     (clear-stream $_test-error-buffered-file->buffer)
730     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
731     68/push 0/imm32
732     68/push 0/imm32
733     89/<- %edx 4/r32/esp
734     (tailor-exit-descriptor %edx 0x10)
735     #
736     (write _test-input-stream "fn foo {\n")
737     (write _test-input-stream "}\n")
738     (write _test-input-stream "sig foo\n")
739     # convert
740     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
741     # registers except esp clobbered at this point
742     # restore ed
743     89/<- %edx 4/r32/esp
744     (flush _test-output-buffered-file)
745     (flush _test-error-buffered-file)
746 #?     # dump _test-error-stream {{{
747 #?     (write 2 "^")
748 #?     (write-stream 2 _test-error-stream)
749 #?     (write 2 "$\n")
750 #?     (rewind-stream _test-error-stream)
751 #?     # }}}
752     # check output
753     (check-stream-equal _test-output-stream  ""  "F - test-function-with-redefined-name-2: output should be empty")
754     (check-next-stream-line-equal _test-error-stream  "fn foo defined more than once"  "F - test-function-with-redefined-name-2: error message")
755     # check that stop(1) was called
756     (check-ints-equal *(edx+4) 2 "F - test-function-with-redefined-name-2: exit status")
757     # don't restore from ebp
758     81 0/subop/add %esp 8/imm32
759     # . epilogue
760     5d/pop-to-ebp
761     c3/return
763 test-function-with-redefined-name-3:
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     (clear-stream _test-error-stream)
773     (clear-stream $_test-error-buffered-file->buffer)
774     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
775     68/push 0/imm32
776     68/push 0/imm32
777     89/<- %edx 4/r32/esp
778     (tailor-exit-descriptor %edx 0x10)
779     #
780     (write _test-input-stream "sig foo\n")
781     (write _test-input-stream "fn foo {\n")
782     (write _test-input-stream "}\n")
783     # convert
784     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
785     # registers except esp clobbered at this point
786     # restore ed
787     89/<- %edx 4/r32/esp
788     (flush _test-output-buffered-file)
789     (flush _test-error-buffered-file)
790 #?     # dump _test-error-stream {{{
791 #?     (write 2 "^")
792 #?     (write-stream 2 _test-error-stream)
793 #?     (write 2 "$\n")
794 #?     (rewind-stream _test-error-stream)
795 #?     # }}}
796     # check output
797     (check-stream-equal _test-output-stream  ""  "F - test-function-with-redefined-name-3: output should be empty")
798     (check-next-stream-line-equal _test-error-stream  "fn foo defined more than once"  "F - test-function-with-redefined-name-3: error message")
799     # check that stop(1) was called
800     (check-ints-equal *(edx+4) 2 "F - test-function-with-redefined-name-3: exit status")
801     # don't restore from ebp
802     81 0/subop/add %esp 8/imm32
803     # . epilogue
804     5d/pop-to-ebp
805     c3/return
807 test-function-with-inout-in-register:
808     # . prologue
809     55/push-ebp
810     89/<- %ebp 4/r32/esp
811     # setup
812     (clear-stream _test-input-stream)
813     (clear-stream $_test-input-buffered-file->buffer)
814     (clear-stream _test-output-stream)
815     (clear-stream $_test-output-buffered-file->buffer)
816     (clear-stream _test-error-stream)
817     (clear-stream $_test-error-buffered-file->buffer)
818     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
819     68/push 0/imm32
820     68/push 0/imm32
821     89/<- %edx 4/r32/esp
822     (tailor-exit-descriptor %edx 0x10)
823     #
824     (write _test-input-stream "fn foo x/eax: int {\n")
825     (write _test-input-stream "}\n")
826     # convert
827     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
828     # registers except esp clobbered at this point
829     # restore ed
830     89/<- %edx 4/r32/esp
831     (flush _test-output-buffered-file)
832     (flush _test-error-buffered-file)
833 #?     # dump _test-error-stream {{{
834 #?     (write 2 "^")
835 #?     (write-stream 2 _test-error-stream)
836 #?     (write 2 "$\n")
837 #?     (rewind-stream _test-error-stream)
838 #?     # }}}
839     # check output
840     (check-stream-equal _test-output-stream  ""  "F - test-function-with-inout-in-register: output should be empty")
841     (check-next-stream-line-equal _test-error-stream  "fn foo: function inout 'x' cannot be in a register"  "F - test-function-with-inout-in-register: error message")
842     # check that stop(1) was called
843     (check-ints-equal *(edx+4) 2 "F - test-function-with-inout-in-register: exit status")
844     # don't restore from ebp
845     81 0/subop/add %esp 8/imm32
846     # . epilogue
847     5d/pop-to-ebp
848     c3/return
850 test-function-with-addr-output:
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     (clear-stream _test-error-stream)
860     (clear-stream $_test-error-buffered-file->buffer)
861     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
862     68/push 0/imm32
863     68/push 0/imm32
864     89/<- %edx 4/r32/esp
865     (tailor-exit-descriptor %edx 0x10)
866     #
867     (write _test-input-stream "fn foo -> _/eax: (addr int) {\n")
868     (write _test-input-stream "}\n")
869     # convert
870     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
871     # registers except esp clobbered at this point
872     # restore ed
873     89/<- %edx 4/r32/esp
874     (flush _test-output-buffered-file)
875     (flush _test-error-buffered-file)
876 #?     # dump _test-error-stream {{{
877 #?     (write 2 "^")
878 #?     (write-stream 2 _test-error-stream)
879 #?     (write 2 "$\n")
880 #?     (rewind-stream _test-error-stream)
881 #?     # }}}
882     # check output
883     (check-stream-equal _test-output-stream  ""  "F - test-function-with-addr-output: output should be empty")
884     (check-next-stream-line-equal _test-error-stream  "fn foo: output cannot have an addr type; that could allow unsafe addresses to escape the function"  "F - test-function-with-addr-output: error message")
885     # check that stop(1) was called
886     (check-ints-equal *(edx+4) 2 "F - test-function-with-addr-output: exit status")
887     # don't restore from ebp
888     81 0/subop/add %esp 8/imm32
889     # . epilogue
890     5d/pop-to-ebp
891     c3/return
893 test-function-with-addr-inout:
894     # . prologue
895     55/push-ebp
896     89/<- %ebp 4/r32/esp
897     # setup
898     (clear-stream _test-input-stream)
899     (clear-stream $_test-input-buffered-file->buffer)
900     (clear-stream _test-output-stream)
901     (clear-stream $_test-output-buffered-file->buffer)
902     (clear-stream _test-error-stream)
903     (clear-stream $_test-error-buffered-file->buffer)
904     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
905     68/push 0/imm32
906     68/push 0/imm32
907     89/<- %edx 4/r32/esp
908     (tailor-exit-descriptor %edx 0x10)
909     #
910     (write _test-input-stream "fn foo a: (addr addr int) {\n")
911     (write _test-input-stream "}\n")
912     # convert
913     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
914     # registers except esp clobbered at this point
915     # restore ed
916     89/<- %edx 4/r32/esp
917     (flush _test-output-buffered-file)
918     (flush _test-error-buffered-file)
919 #?     # dump _test-error-stream {{{
920 #?     (write 2 "^")
921 #?     (write-stream 2 _test-error-stream)
922 #?     (write 2 "$\n")
923 #?     (rewind-stream _test-error-stream)
924 #?     # }}}
925     # check output
926     (check-stream-equal _test-output-stream  ""  "F - test-function-with-addr-inout: output should be empty")
927     (check-next-stream-line-equal _test-error-stream  "fn foo: inout 'a' cannot contain 'addr' anywhere in the type except the first word; that could allow unsafe addresses to escape the function"  "F - test-function-with-addr-inout: error message")
928     # check that stop(1) was called
929     (check-ints-equal *(edx+4) 2 "F - test-function-with-addr-inout: exit status")
930     # don't restore from ebp
931     81 0/subop/add %esp 8/imm32
932     # . epilogue
933     5d/pop-to-ebp
934     c3/return
936 test-function-with-addr-inout-2:
937     # . prologue
938     55/push-ebp
939     89/<- %ebp 4/r32/esp
940     # setup
941     (clear-stream _test-input-stream)
942     (clear-stream $_test-input-buffered-file->buffer)
943     (clear-stream _test-output-stream)
944     (clear-stream $_test-output-buffered-file->buffer)
945     (clear-stream _test-error-stream)
946     (clear-stream $_test-error-buffered-file->buffer)
947     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
948     68/push 0/imm32
949     68/push 0/imm32
950     89/<- %edx 4/r32/esp
951     (tailor-exit-descriptor %edx 0x10)
952     #
953     (write _test-input-stream "fn foo a: (addr array addr int) {\n")
954     (write _test-input-stream "}\n")
955     # convert
956     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
957     # registers except esp clobbered at this point
958     # restore ed
959     89/<- %edx 4/r32/esp
960     (flush _test-output-buffered-file)
961     (flush _test-error-buffered-file)
962 #?     # dump _test-error-stream {{{
963 #?     (write 2 "^")
964 #?     (write-stream 2 _test-error-stream)
965 #?     (write 2 "$\n")
966 #?     (rewind-stream _test-error-stream)
967 #?     # }}}
968     # check output
969     (check-stream-equal _test-output-stream  ""  "F - test-function-with-addr-inout-2: output should be empty")
970     (check-next-stream-line-equal _test-error-stream  "fn foo: inout 'a' cannot contain 'addr' anywhere in the type except the first word; that could allow unsafe addresses to escape the function"  "F - test-function-with-addr-inout-2: error message")
971     # check that stop(1) was called
972     (check-ints-equal *(edx+4) 2 "F - test-function-with-addr-inout-2: exit status")
973     # don't restore from ebp
974     81 0/subop/add %esp 8/imm32
975     # . epilogue
976     5d/pop-to-ebp
977     c3/return
979 test-function-with-addr-inout-3:
980     # . prologue
981     55/push-ebp
982     89/<- %ebp 4/r32/esp
983     # setup
984     (clear-stream _test-input-stream)
985     (clear-stream $_test-input-buffered-file->buffer)
986     (clear-stream _test-output-stream)
987     (clear-stream $_test-output-buffered-file->buffer)
988     (clear-stream _test-error-stream)
989     (clear-stream $_test-error-buffered-file->buffer)
990     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
991     68/push 0/imm32
992     68/push 0/imm32
993     89/<- %edx 4/r32/esp
994     (tailor-exit-descriptor %edx 0x10)
995     #
996     (write _test-input-stream "fn foo a: (addr array (addr int) 3) {\n")
997     (write _test-input-stream "}\n")
998     # convert
999     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
1000     # registers except esp clobbered at this point
1001     # restore ed
1002     89/<- %edx 4/r32/esp
1003     (flush _test-output-buffered-file)
1004     (flush _test-error-buffered-file)
1005 #?     # dump _test-error-stream {{{
1006 #?     (write 2 "^")
1007 #?     (write-stream 2 _test-error-stream)
1008 #?     (write 2 "$\n")
1009 #?     (rewind-stream _test-error-stream)
1010 #?     # }}}
1011     # check output
1012     (check-stream-equal _test-output-stream  ""  "F - test-function-with-addr-inout-3: output should be empty")
1013     (check-next-stream-line-equal _test-error-stream  "fn foo: inout 'a' cannot contain 'addr' anywhere in the type except the first word; that could allow unsafe addresses to escape the function"  "F - test-function-with-addr-inout-3: error message")
1014     # check that stop(1) was called
1015     (check-ints-equal *(edx+4) 2 "F - test-function-with-addr-inout-3: exit status")
1016     # don't restore from ebp
1017     81 0/subop/add %esp 8/imm32
1018     # . epilogue
1019     5d/pop-to-ebp
1020     c3/return
1022 test-function-with-addr-inout-4:
1023     # . prologue
1024     55/push-ebp
1025     89/<- %ebp 4/r32/esp
1026     # setup
1027     (clear-stream _test-input-stream)
1028     (clear-stream $_test-input-buffered-file->buffer)
1029     (clear-stream _test-output-stream)
1030     (clear-stream $_test-output-buffered-file->buffer)
1031     (clear-stream _test-error-stream)
1032     (clear-stream $_test-error-buffered-file->buffer)
1033     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
1034     68/push 0/imm32
1035     68/push 0/imm32
1036     89/<- %edx 4/r32/esp
1037     (tailor-exit-descriptor %edx 0x10)
1038     #
1039     (write _test-input-stream "fn foo a: (array (addr int) 3) {\n")
1040     (write _test-input-stream "}\n")
1041     # convert
1042     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
1043     # registers except esp clobbered at this point
1044     # restore ed
1045     89/<- %edx 4/r32/esp
1046     (flush _test-output-buffered-file)
1047     (flush _test-error-buffered-file)
1048 #?     # dump _test-error-stream {{{
1049 #?     (write 2 "^")
1050 #?     (write-stream 2 _test-error-stream)
1051 #?     (write 2 "$\n")
1052 #?     (rewind-stream _test-error-stream)
1053 #?     # }}}
1054     # check output
1055     (check-stream-equal _test-output-stream  ""  "F - test-function-with-addr-inout-4: output should be empty")
1056     (check-next-stream-line-equal _test-error-stream  "fn foo: inout 'a' cannot contain 'addr' anywhere in the type except the first word; that could allow unsafe addresses to escape the function"  "F - test-function-with-addr-inout-4: error message")
1057     # check that stop(1) was called
1058     (check-ints-equal *(edx+4) 2 "F - test-function-with-addr-inout-4: exit status")
1059     # don't restore from ebp
1060     81 0/subop/add %esp 8/imm32
1061     # . epilogue
1062     5d/pop-to-ebp
1063     c3/return
1065 # 'main' is an exception
1066 test-function-main-with-addr-inout:
1067     # . prologue
1068     55/push-ebp
1069     89/<- %ebp 4/r32/esp
1070     # setup
1071     (clear-stream _test-input-stream)
1072     (clear-stream $_test-input-buffered-file->buffer)
1073     (clear-stream _test-output-stream)
1074     (clear-stream $_test-output-buffered-file->buffer)
1075     #
1076     (write _test-input-stream "fn main a: (addr addr int) {\n")
1077     (write _test-input-stream "}\n")
1078     # convert
1079     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
1080     (flush _test-output-buffered-file)
1081     # no errors
1082     # . epilogue
1083     89/<- %esp 5/r32/ebp
1084     5d/pop-to-ebp
1085     c3/return
1087 # 'lookup' is an exception, but only in signatures
1088 test-signature-lookup-with-addr-inout:
1089     # . prologue
1090     55/push-ebp
1091     89/<- %ebp 4/r32/esp
1092     # setup
1093     (clear-stream _test-input-stream)
1094     (clear-stream $_test-input-buffered-file->buffer)
1095     (clear-stream _test-output-stream)
1096     (clear-stream $_test-output-buffered-file->buffer)
1097     #
1098     (write _test-input-stream "sig lookup h: (handle _T) -> _/eax: (addr _T)\n")
1099     # convert
1100     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
1101     (flush _test-output-buffered-file)
1102     # no errors
1103     # . epilogue
1104     89/<- %esp 5/r32/ebp
1105     5d/pop-to-ebp
1106     c3/return
1108 test-convert-function-with-arg-and-body:
1109     # . prologue
1110     55/push-ebp
1111     89/<- %ebp 4/r32/esp
1112     # setup
1113     (clear-stream _test-input-stream)
1114     (clear-stream $_test-input-buffered-file->buffer)
1115     (clear-stream _test-output-stream)
1116     (clear-stream $_test-output-buffered-file->buffer)
1117     #
1118     (write _test-input-stream "fn foo n: int {\n")
1119     (write _test-input-stream "  increment n\n")
1120     (write _test-input-stream "}\n")
1121     # convert
1122     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
1123     (flush _test-output-buffered-file)
1124 #?     # dump _test-output-stream {{{
1125 #?     (write 2 "^")
1126 #?     (write-stream 2 _test-output-stream)
1127 #?     (write 2 "$\n")
1128 #?     (rewind-stream _test-output-stream)
1129 #?     # }}}
1130     # check output
1131     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg-and-body/0")
1132     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg-and-body/1")
1133     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg-and-body/2")
1134     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg-and-body/3")
1135     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-arg-and-body/4")
1136     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-arg-and-body/5")
1137     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-arg-and-body/6")
1138     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-arg-and-body/7")
1139     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-arg-and-body/8")
1140     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg-and-body/9")
1141     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg-and-body/10")
1142     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg-and-body/11")
1143     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg-and-body/12")
1144     # . epilogue
1145     89/<- %esp 5/r32/ebp
1146     5d/pop-to-ebp
1147     c3/return
1149 test-convert-function-distinguishes-args:
1150     # . prologue
1151     55/push-ebp
1152     89/<- %ebp 4/r32/esp
1153     # setup
1154     (clear-stream _test-input-stream)
1155     (clear-stream $_test-input-buffered-file->buffer)
1156     (clear-stream _test-output-stream)
1157     (clear-stream $_test-output-buffered-file->buffer)
1158     #
1159     (write _test-input-stream "fn foo a: int, b: int {\n")
1160     (write _test-input-stream "  increment b\n")
1161     (write _test-input-stream "}\n")
1162     # convert
1163     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
1164     (flush _test-output-buffered-file)
1165 #?     # dump _test-output-stream {{{
1166 #?     (write 2 "^")
1167 #?     (write-stream 2 _test-output-stream)
1168 #?     (write 2 "$\n")
1169 #?     (rewind-stream _test-output-stream)
1170 #?     # }}}
1171     # check output
1172     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-distinguishes-args/0")
1173     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-distinguishes-args/1")
1174     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-distinguishes-args/2")
1175     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-distinguishes-args/3")
1176     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-distinguishes-args/4")
1177     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-distinguishes-args/5")
1178     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x0000000c)"  "F - test-convert-function-distinguishes-args/6")
1179     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-distinguishes-args/7")
1180     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-distinguishes-args/8")
1181     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-distinguishes-args/9")
1182     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-distinguishes-args/10")
1183     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-distinguishes-args/11")
1184     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-distinguishes-args/12")
1185     # . epilogue
1186     89/<- %esp 5/r32/ebp
1187     5d/pop-to-ebp
1188     c3/return
1190 test-convert-function-with-return-literal:
1191     # . prologue
1192     55/push-ebp
1193     89/<- %ebp 4/r32/esp
1194     # setup
1195     (clear-stream _test-input-stream)
1196     (clear-stream $_test-input-buffered-file->buffer)
1197     (clear-stream _test-output-stream)
1198     (clear-stream $_test-output-buffered-file->buffer)
1199     #
1200     (write _test-input-stream "fn foo -> _/eax: int {\n")
1201     (write _test-input-stream "  return 0\n")
1202     (write _test-input-stream "}\n")
1203     # convert
1204     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
1205     (flush _test-output-buffered-file)
1206 #?     # dump _test-output-stream {{{
1207 #?     (write 2 "^")
1208 #?     (write-stream 2 _test-output-stream)
1209 #?     (write 2 "$\n")
1210 #?     (rewind-stream _test-output-stream)
1211 #?     # }}}
1212     # check output
1213     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-return-literal/0")
1214     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-return-literal/1")
1215     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-return-literal/2")
1216     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-return-literal/3")
1217     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-return-literal/4")
1218     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-return-literal/5")
1219     (check-next-stream-line-equal _test-output-stream "    c7 0/subop/copy %eax 0/imm32"  "F - test-convert-function-with-return-literal/6")
1220     (check-next-stream-line-equal _test-output-stream "    e9/jump $foo:0x00000001:break/disp32"  "F - test-convert-function-with-return-literal/7")
1221     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-return-literal/8")
1222     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-return-literal/9")
1223     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-return-literal/10")
1224     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-return-literal/11")
1225     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-return-literal/12")
1226     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-return-literal/13")
1227     # . epilogue
1228     89/<- %esp 5/r32/ebp
1229     5d/pop-to-ebp
1230     c3/return
1232 test-convert-function-with-return:
1233     # . prologue
1234     55/push-ebp
1235     89/<- %ebp 4/r32/esp
1236     # setup
1237     (clear-stream _test-input-stream)
1238     (clear-stream $_test-input-buffered-file->buffer)
1239     (clear-stream _test-output-stream)
1240     (clear-stream $_test-output-buffered-file->buffer)
1241     #
1242     (write _test-input-stream "fn foo -> _/eax: int {\n")
1243     (write _test-input-stream "  var y: int\n")
1244     (write _test-input-stream "  return y\n")
1245     (write _test-input-stream "}\n")
1246     # convert
1247     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
1248     (flush _test-output-buffered-file)
1249 #?     # dump _test-output-stream {{{
1250 #?     (write 2 "^")
1251 #?     (write-stream 2 _test-output-stream)
1252 #?     (write 2 "$\n")
1253 #?     (rewind-stream _test-output-stream)
1254 #?     # }}}
1255     # check output
1256     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-return/0")
1257     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-return/1")
1258     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-return/2")
1259     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-return/3")
1260     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-return/4")
1261     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-return/5")
1262     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-return/6")  # y
1263     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0xfffffffc) 0x00000000/r32" "F - test-convert-function-with-return/7")
1264     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-return/8")
1265     (check-next-stream-line-equal _test-output-stream "    e9/jump $foo:0x00000001:break/disp32"  "F - test-convert-function-with-return/9")
1266     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-return/10")
1267     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-return/11")
1268     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-return/12")
1269     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-return/13")
1270     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-return/14")
1271     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-return/15")
1272     # . epilogue
1273     89/<- %esp 5/r32/ebp
1274     5d/pop-to-ebp
1275     c3/return
1277 test-convert-function-with-return-float:
1278     # . prologue
1279     55/push-ebp
1280     89/<- %ebp 4/r32/esp
1281     # setup
1282     (clear-stream _test-input-stream)
1283     (clear-stream $_test-input-buffered-file->buffer)
1284     (clear-stream _test-output-stream)
1285     (clear-stream $_test-output-buffered-file->buffer)
1286     #
1287     (write _test-input-stream "fn foo -> _/xmm0: float {\n")
1288     (write _test-input-stream "  var y: float\n")
1289     (write _test-input-stream "  return y\n")
1290     (write _test-input-stream "}\n")
1291     # convert
1292     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
1293     (flush _test-output-buffered-file)
1294 #?     # dump _test-output-stream {{{
1295 #?     (write 2 "^")
1296 #?     (write-stream 2 _test-output-stream)
1297 #?     (write 2 "$\n")
1298 #?     (rewind-stream _test-output-stream)
1299 #?     # }}}
1300     # check output
1301     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-return/0")
1302     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-return/1")
1303     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-return/2")
1304     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-return/3")
1305     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-return/4")
1306     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-return/5")
1307     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-return/6")  # y
1308     (check-next-stream-line-equal _test-output-stream "    f3 0f 10/-> *(ebp+0xfffffffc) 0x00000000/x32" "F - test-convert-function-with-return/7")
1309     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-return/8")
1310     (check-next-stream-line-equal _test-output-stream "    e9/jump $foo:0x00000001:break/disp32"  "F - test-convert-function-with-return/9")
1311     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-return/10")
1312     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-return/11")
1313     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-return/12")
1314     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-return/13")
1315     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-return/14")
1316     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-return/15")
1317     # . epilogue
1318     89/<- %esp 5/r32/ebp
1319     5d/pop-to-ebp
1320     c3/return
1322 test-convert-function-with-return-register:
1323     # . prologue
1324     55/push-ebp
1325     89/<- %ebp 4/r32/esp
1326     # setup
1327     (clear-stream _test-input-stream)
1328     (clear-stream $_test-input-buffered-file->buffer)
1329     (clear-stream _test-output-stream)
1330     (clear-stream $_test-output-buffered-file->buffer)
1331     #
1332     (write _test-input-stream "fn foo -> _/eax: int {\n")
1333     (write _test-input-stream "  var y/eax: int <- copy 3\n")
1334     (write _test-input-stream "  return y\n")
1335     (write _test-input-stream "}\n")
1336     # convert
1337     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
1338     (flush _test-output-buffered-file)
1339 #?     # dump _test-output-stream {{{
1340 #?     (write 2 "^")
1341 #?     (write-stream 2 _test-output-stream)
1342 #?     (write 2 "$\n")
1343 #?     (rewind-stream _test-output-stream)
1344 #?     # }}}
1345     # check output
1346     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-return-register/0")
1347     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-return-register/1")
1348     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-return-register/2")
1349     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-return-register/3")
1350     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-return-register/4")
1351     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-return-register/5")
1352     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-function-with-return-register/6")
1353     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-convert-function-with-return-register/7")
1354     (check-next-stream-line-equal _test-output-stream "    8b/-> %eax 0x00000000/r32" "F - test-convert-function-with-return-register/8")
1355     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 4/imm32"  "F - test-convert-function-with-return-register/9")
1356     (check-next-stream-line-equal _test-output-stream "    e9/jump $foo:0x00000001:break/disp32"  "F - test-convert-function-with-return-register/10")
1357     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-return-register/11")
1358     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-return-register/12")
1359     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-return-register/13")
1360     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-return-register/14")
1361     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-return-register/15")
1362     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-return-register/16")
1363     # . epilogue
1364     89/<- %esp 5/r32/ebp
1365     5d/pop-to-ebp
1366     c3/return
1368 test-function-with-output-without-register:
1369     # . prologue
1370     55/push-ebp
1371     89/<- %ebp 4/r32/esp
1372     # setup
1373     (clear-stream _test-input-stream)
1374     (clear-stream $_test-input-buffered-file->buffer)
1375     (clear-stream _test-output-stream)
1376     (clear-stream $_test-output-buffered-file->buffer)
1377     (clear-stream _test-error-stream)
1378     (clear-stream $_test-error-buffered-file->buffer)
1379     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
1380     68/push 0/imm32
1381     68/push 0/imm32
1382     89/<- %edx 4/r32/esp
1383     (tailor-exit-descriptor %edx 0x10)
1384     #
1385     (write _test-input-stream "fn foo -> _: int {\n")
1386     (write _test-input-stream "}\n")
1387     # convert
1388     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
1389     # registers except esp clobbered at this point
1390     # restore ed
1391     89/<- %edx 4/r32/esp
1392     (flush _test-output-buffered-file)
1393     (flush _test-error-buffered-file)
1394 #?     # dump _test-error-stream {{{
1395 #?     (write 2 "^")
1396 #?     (write-stream 2 _test-error-stream)
1397 #?     (write 2 "$\n")
1398 #?     (rewind-stream _test-error-stream)
1399 #?     # }}}
1400     # check output
1401     (check-stream-equal _test-output-stream  ""  "F - test-function-with-output-without-register: output should be empty")
1402     (check-next-stream-line-equal _test-error-stream  "fn foo: function output '_' must be in a register, in instruction 'fn foo -> _: int {"  "F - test-function-with-output-without-register: error message")
1403     # check that stop(1) was called
1404     (check-ints-equal *(edx+4) 2 "F - test-function-with-output-without-register: exit status")
1405     # don't restore from ebp
1406     81 0/subop/add %esp 8/imm32
1407     # . epilogue
1408     5d/pop-to-ebp
1409     c3/return
1411 test-function-with-outputs-in-conflicting-registers:
1412     # . prologue
1413     55/push-ebp
1414     89/<- %ebp 4/r32/esp
1415     # setup
1416     (clear-stream _test-input-stream)
1417     (clear-stream $_test-input-buffered-file->buffer)
1418     (clear-stream _test-output-stream)
1419     (clear-stream $_test-output-buffered-file->buffer)
1420     (clear-stream _test-error-stream)
1421     (clear-stream $_test-error-buffered-file->buffer)
1422     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
1423     68/push 0/imm32
1424     68/push 0/imm32
1425     89/<- %edx 4/r32/esp
1426     (tailor-exit-descriptor %edx 0x10)
1427     #
1428     (write _test-input-stream "fn foo -> _/eax: int, _/eax: int {\n")
1429     (write _test-input-stream "}\n")
1430     # convert
1431     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
1432     # registers except esp clobbered at this point
1433     # restore ed
1434     89/<- %edx 4/r32/esp
1435     (flush _test-output-buffered-file)
1436     (flush _test-error-buffered-file)
1437 #?     # dump _test-error-stream {{{
1438 #?     (write 2 "^")
1439 #?     (write-stream 2 _test-error-stream)
1440 #?     (write 2 "$\n")
1441 #?     (rewind-stream _test-error-stream)
1442 #?     # }}}
1443     # check output
1444     (check-stream-equal _test-output-stream  ""  "F - test-function-with-outputs-in-conflicting-registers: output should be empty")
1445     (check-next-stream-line-equal _test-error-stream  "fn foo: outputs must be in unique registers"  "F - test-function-with-outputs-in-conflicting-registers: error message")
1446     # check that stop(1) was called
1447     (check-ints-equal *(edx+4) 2 "F - test-function-with-outputs-in-conflicting-registers: exit status")
1448     # don't restore from ebp
1449     81 0/subop/add %esp 8/imm32
1450     # . epilogue
1451     5d/pop-to-ebp
1452     c3/return
1454 test-function-with-named-output:
1455     # . prologue
1456     55/push-ebp
1457     89/<- %ebp 4/r32/esp
1458     # setup
1459     (clear-stream _test-input-stream)
1460     (clear-stream $_test-input-buffered-file->buffer)
1461     (clear-stream _test-output-stream)
1462     (clear-stream $_test-output-buffered-file->buffer)
1463     (clear-stream _test-error-stream)
1464     (clear-stream $_test-error-buffered-file->buffer)
1465     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
1466     68/push 0/imm32
1467     68/push 0/imm32
1468     89/<- %edx 4/r32/esp
1469     (tailor-exit-descriptor %edx 0x10)
1470     #
1471     (write _test-input-stream "fn foo -> x/eax: int {\n")
1472     (write _test-input-stream "  return 0\n")
1473     (write _test-input-stream "}\n")
1474     # convert
1475     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
1476     # registers except esp clobbered at this point
1477     # restore ed
1478     89/<- %edx 4/r32/esp
1479     (flush _test-output-buffered-file)
1480     (flush _test-error-buffered-file)
1481 #?     # dump _test-error-stream {{{
1482 #?     (write 2 "^")
1483 #?     (write-stream 2 _test-error-stream)
1484 #?     (write 2 "$\n")
1485 #?     (rewind-stream _test-error-stream)
1486 #?     # }}}
1487     # check output
1488     (check-stream-equal _test-output-stream  ""  "F - test-function-with-named-output: output should be empty")
1489     (check-next-stream-line-equal _test-error-stream  "fn foo: function outputs cannot be named; rename 'x' in the header to '_'"  "F - test-function-with-named-output: error message")
1490     # check that stop(1) was called
1491     (check-ints-equal *(edx+4) 2 "F - test-function-with-named-output: exit status")
1492     # don't restore from ebp
1493     81 0/subop/add %esp 8/imm32
1494     # . epilogue
1495     5d/pop-to-ebp
1496     c3/return
1498 test-return-with-wrong-type:
1499     # . prologue
1500     55/push-ebp
1501     89/<- %ebp 4/r32/esp
1502     # setup
1503     (clear-stream _test-input-stream)
1504     (clear-stream $_test-input-buffered-file->buffer)
1505     (clear-stream _test-output-stream)
1506     (clear-stream $_test-output-buffered-file->buffer)
1507     (clear-stream _test-error-stream)
1508     (clear-stream $_test-error-buffered-file->buffer)
1509     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
1510     68/push 0/imm32
1511     68/push 0/imm32
1512     89/<- %edx 4/r32/esp
1513     (tailor-exit-descriptor %edx 0x10)
1514     #
1515     (write _test-input-stream "fn foo -> _/eax: int {\n")
1516     (write _test-input-stream "  var x/eax: boolean <- copy 0\n")
1517     (write _test-input-stream "  return x\n")
1518     (write _test-input-stream "}\n")
1519     # convert
1520     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
1521     # registers except esp clobbered at this point
1522     # restore ed
1523     89/<- %edx 4/r32/esp
1524     (flush _test-output-buffered-file)
1525     (flush _test-error-buffered-file)
1526 #?     # dump _test-error-stream {{{
1527 #?     (write 2 "^")
1528 #?     (write-stream 2 _test-error-stream)
1529 #?     (write 2 "$\n")
1530 #?     (rewind-stream _test-error-stream)
1531 #?     # }}}
1532     # check output
1533     (check-stream-equal _test-output-stream  ""  "F - test-return-with-wrong-type: output should be empty")
1534     (check-next-stream-line-equal _test-error-stream  "fn foo: return: 'x' has the wrong type"  "F - test-return-with-wrong-type: error message")
1535     # check that stop(1) was called
1536     (check-ints-equal *(edx+4) 2 "F - test-return-with-wrong-type: exit status")
1537     # don't restore from ebp
1538     81 0/subop/add %esp 8/imm32
1539     # . epilogue
1540     5d/pop-to-ebp
1541     c3/return
1543 test-missing-return:
1544     # . prologue
1545     55/push-ebp
1546     89/<- %ebp 4/r32/esp
1547     # setup
1548     (clear-stream _test-input-stream)
1549     (clear-stream $_test-input-buffered-file->buffer)
1550     (clear-stream _test-output-stream)
1551     (clear-stream $_test-output-buffered-file->buffer)
1552     (clear-stream _test-error-stream)
1553     (clear-stream $_test-error-buffered-file->buffer)
1554     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
1555     68/push 0/imm32
1556     68/push 0/imm32
1557     89/<- %edx 4/r32/esp
1558     (tailor-exit-descriptor %edx 0x10)
1559     #
1560     (write _test-input-stream "fn foo -> _/eax: int {\n")
1561     (write _test-input-stream "  var x/eax: boolean <- copy 0\n")
1562     (write _test-input-stream "}\n")
1563     # convert
1564     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
1565     # registers except esp clobbered at this point
1566     # restore ed
1567     89/<- %edx 4/r32/esp
1568     (flush _test-output-buffered-file)
1569     (flush _test-error-buffered-file)
1570 #?     # dump _test-error-stream {{{
1571 #?     (write 2 "^")
1572 #?     (write-stream 2 _test-error-stream)
1573 #?     (write 2 "$\n")
1574 #?     (rewind-stream _test-error-stream)
1575 #?     # }}}
1576     # check output
1577     (check-stream-equal _test-output-stream  ""  "F - test-missing-return: output should be empty")
1578     (check-next-stream-line-equal _test-error-stream  "fn foo: final statement should be a 'return'"  "F - test-missing-return: error message")
1579     # check that stop(1) was called
1580     (check-ints-equal *(edx+4) 2 "F - test-missing-return: exit status")
1581     # don't restore from ebp
1582     81 0/subop/add %esp 8/imm32
1583     # . epilogue
1584     5d/pop-to-ebp
1585     c3/return
1587 test-missing-return-2:
1588     # . prologue
1589     55/push-ebp
1590     89/<- %ebp 4/r32/esp
1591     # setup
1592     (clear-stream _test-input-stream)
1593     (clear-stream $_test-input-buffered-file->buffer)
1594     (clear-stream _test-output-stream)
1595     (clear-stream $_test-output-buffered-file->buffer)
1596     (clear-stream _test-error-stream)
1597     (clear-stream $_test-error-buffered-file->buffer)
1598     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
1599     68/push 0/imm32
1600     68/push 0/imm32
1601     89/<- %edx 4/r32/esp
1602     (tailor-exit-descriptor %edx 0x10)
1603     #
1604     (write _test-input-stream "fn foo -> _/eax: int {\n")
1605     (write _test-input-stream "}\n")
1606     # convert
1607     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
1608     # registers except esp clobbered at this point
1609     # restore ed
1610     89/<- %edx 4/r32/esp
1611     (flush _test-output-buffered-file)
1612     (flush _test-error-buffered-file)
1613 #?     # dump _test-error-stream {{{
1614 #?     (write 2 "^")
1615 #?     (write-stream 2 _test-error-stream)
1616 #?     (write 2 "$\n")
1617 #?     (rewind-stream _test-error-stream)
1618 #?     # }}}
1619     # check output
1620     (check-stream-equal _test-output-stream  ""  "F - test-missing-return-2: output should be empty")
1621     (check-next-stream-line-equal _test-error-stream  "fn foo: final statement should be a 'return'"  "F - test-missing-return-2: error message")
1622     # check that stop(1) was called
1623     (check-ints-equal *(edx+4) 2 "F - test-missing-return-2: exit status")
1624     # don't restore from ebp
1625     81 0/subop/add %esp 8/imm32
1626     # . epilogue
1627     5d/pop-to-ebp
1628     c3/return
1630 test-early-exit-without-return:
1631     # . prologue
1632     55/push-ebp
1633     89/<- %ebp 4/r32/esp
1634     # setup
1635     (clear-stream _test-input-stream)
1636     (clear-stream $_test-input-buffered-file->buffer)
1637     (clear-stream _test-output-stream)
1638     (clear-stream $_test-output-buffered-file->buffer)
1639     (clear-stream _test-error-stream)
1640     (clear-stream $_test-error-buffered-file->buffer)
1641     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
1642     68/push 0/imm32
1643     68/push 0/imm32
1644     89/<- %edx 4/r32/esp
1645     (tailor-exit-descriptor %edx 0x10)
1646     #
1647     (write _test-input-stream "fn foo -> _/eax: int {\n")
1648     (write _test-input-stream "  break\n")
1649     (write _test-input-stream "  return 0\n")
1650     (write _test-input-stream "}\n")
1651     # convert
1652     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
1653     # registers except esp clobbered at this point
1654     # restore ed
1655     89/<- %edx 4/r32/esp
1656     (flush _test-output-buffered-file)
1657     (flush _test-error-buffered-file)
1658 #?     # dump _test-error-stream {{{
1659 #?     (write 2 "^")
1660 #?     (write-stream 2 _test-error-stream)
1661 #?     (write 2 "$\n")
1662 #?     (rewind-stream _test-error-stream)
1663 #?     # }}}
1664     # check output
1665     (check-stream-equal _test-output-stream  ""  "F - test-early-exit-without-return: output should be empty")
1666     (check-next-stream-line-equal _test-error-stream  "fn foo has outputs, so you cannot 'break' out of the outermost block. Use 'return'."  "F - test-early-exit-without-return: error message")
1667     # check that stop(1) was called
1668     (check-ints-equal *(edx+4) 2 "F - test-early-exit-without-return: exit status")
1669     # don't restore from ebp
1670     81 0/subop/add %esp 8/imm32
1671     # . epilogue
1672     5d/pop-to-ebp
1673     c3/return
1675 test-return-with-too-few-inouts:
1676     # . prologue
1677     55/push-ebp
1678     89/<- %ebp 4/r32/esp
1679     # setup
1680     (clear-stream _test-input-stream)
1681     (clear-stream $_test-input-buffered-file->buffer)
1682     (clear-stream _test-output-stream)
1683     (clear-stream $_test-output-buffered-file->buffer)
1684     (clear-stream _test-error-stream)
1685     (clear-stream $_test-error-buffered-file->buffer)
1686     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
1687     68/push 0/imm32
1688     68/push 0/imm32
1689     89/<- %edx 4/r32/esp
1690     (tailor-exit-descriptor %edx 0x10)
1691     #
1692     (write _test-input-stream "fn foo -> _/eax: int {\n")
1693     (write _test-input-stream "  return\n")
1694     (write _test-input-stream "}\n")
1695     # convert
1696     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
1697     # registers except esp clobbered at this point
1698     # restore ed
1699     89/<- %edx 4/r32/esp
1700     (flush _test-output-buffered-file)
1701     (flush _test-error-buffered-file)
1702 #?     # dump _test-error-stream {{{
1703 #?     (write 2 "^")
1704 #?     (write-stream 2 _test-error-stream)
1705 #?     (write 2 "$\n")
1706 #?     (rewind-stream _test-error-stream)
1707 #?     # }}}
1708     # check output
1709     (check-stream-equal _test-output-stream  ""  "F - test-return-with-too-few-inouts: output should be empty")
1710     (check-next-stream-line-equal _test-error-stream  "fn foo: return: too few inouts"  "F - test-return-with-too-few-inouts: error message")
1711     # check that stop(1) was called
1712     (check-ints-equal *(edx+4) 2 "F - test-return-with-too-few-inouts: exit status")
1713     # don't restore from ebp
1714     81 0/subop/add %esp 8/imm32
1715     # . epilogue
1716     5d/pop-to-ebp
1717     c3/return
1719 test-return-with-too-many-inouts:
1720     # . prologue
1721     55/push-ebp
1722     89/<- %ebp 4/r32/esp
1723     # setup
1724     (clear-stream _test-input-stream)
1725     (clear-stream $_test-input-buffered-file->buffer)
1726     (clear-stream _test-output-stream)
1727     (clear-stream $_test-output-buffered-file->buffer)
1728     (clear-stream _test-error-stream)
1729     (clear-stream $_test-error-buffered-file->buffer)
1730     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
1731     68/push 0/imm32
1732     68/push 0/imm32
1733     89/<- %edx 4/r32/esp
1734     (tailor-exit-descriptor %edx 0x10)
1735     #
1736     (write _test-input-stream "fn foo -> _/eax: int {\n")
1737     (write _test-input-stream "  return 0, 0\n")
1738     (write _test-input-stream "}\n")
1739     # convert
1740     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
1741     # registers except esp clobbered at this point
1742     # restore ed
1743     89/<- %edx 4/r32/esp
1744     (flush _test-output-buffered-file)
1745     (flush _test-error-buffered-file)
1746 #?     # dump _test-error-stream {{{
1747 #?     (write 2 "^")
1748 #?     (write-stream 2 _test-error-stream)
1749 #?     (write 2 "$\n")
1750 #?     (rewind-stream _test-error-stream)
1751 #?     # }}}
1752     # check output
1753     (check-stream-equal _test-output-stream  ""  "F - test-return-with-too-many-inouts: output should be empty")
1754     (check-next-stream-line-equal _test-error-stream  "fn foo: return: too many inouts"  "F - test-return-with-too-many-inouts: error message")
1755     # check that stop(1) was called
1756     (check-ints-equal *(edx+4) 2 "F - test-return-with-too-many-inouts: exit status")
1757     # don't restore from ebp
1758     81 0/subop/add %esp 8/imm32
1759     # . epilogue
1760     5d/pop-to-ebp
1761     c3/return
1763 test-return-unavailable-value:
1764     # . prologue
1765     55/push-ebp
1766     89/<- %ebp 4/r32/esp
1767     # setup
1768     (clear-stream _test-input-stream)
1769     (clear-stream $_test-input-buffered-file->buffer)
1770     (clear-stream _test-output-stream)
1771     (clear-stream $_test-output-buffered-file->buffer)
1772     (clear-stream _test-error-stream)
1773     (clear-stream $_test-error-buffered-file->buffer)
1774     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
1775     68/push 0/imm32
1776     68/push 0/imm32
1777     89/<- %edx 4/r32/esp
1778     (tailor-exit-descriptor %edx 0x10)
1779     #
1780     (write _test-input-stream "fn foo -> _/eax: int, _/ecx: int {\n")
1781     (write _test-input-stream "  var x/eax: int <- copy 0\n")
1782     (write _test-input-stream "  var y/ecx: int <- copy 0\n")
1783     (write _test-input-stream "  return y, x\n")
1784     (write _test-input-stream "}\n")
1785     # convert
1786     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
1787     # registers except esp clobbered at this point
1788     # restore ed
1789     89/<- %edx 4/r32/esp
1790     (flush _test-output-buffered-file)
1791     (flush _test-error-buffered-file)
1792 #?     # dump _test-error-stream {{{
1793 #?     (write 2 "^")
1794 #?     (write-stream 2 _test-error-stream)
1795 #?     (write 2 "$\n")
1796 #?     (rewind-stream _test-error-stream)
1797 #?     # }}}
1798     # check output
1799     (check-stream-equal _test-output-stream  ""  "F - test-return-unavailable-value: output should be empty")
1800     (check-next-stream-line-equal _test-error-stream  "fn foo: return: 'x' is no longer available"  "F - test-return-unavailable-value: error message")
1801     # check that stop(1) was called
1802     (check-ints-equal *(edx+4) 2 "F - test-return-unavailable-value: exit status")
1803     # don't restore from ebp
1804     81 0/subop/add %esp 8/imm32
1805     # . epilogue
1806     5d/pop-to-ebp
1807     c3/return
1809 test-return-literal-to-float:
1810     # . prologue
1811     55/push-ebp
1812     89/<- %ebp 4/r32/esp
1813     # setup
1814     (clear-stream _test-input-stream)
1815     (clear-stream $_test-input-buffered-file->buffer)
1816     (clear-stream _test-output-stream)
1817     (clear-stream $_test-output-buffered-file->buffer)
1818     (clear-stream _test-error-stream)
1819     (clear-stream $_test-error-buffered-file->buffer)
1820     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
1821     68/push 0/imm32
1822     68/push 0/imm32
1823     89/<- %edx 4/r32/esp
1824     (tailor-exit-descriptor %edx 0x10)
1825     #
1826     (write _test-input-stream "fn foo -> _/xmm0: float {\n")
1827     (write _test-input-stream "  return 0\n")
1828     (write _test-input-stream "}\n")
1829     # convert
1830     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
1831     # registers except esp clobbered at this point
1832     # restore ed
1833     89/<- %edx 4/r32/esp
1834     (flush _test-output-buffered-file)
1835     (flush _test-error-buffered-file)
1836 #?     # dump _test-error-stream {{{
1837 #?     (write 2 "^")
1838 #?     (write-stream 2 _test-error-stream)
1839 #?     (write 2 "$\n")
1840 #?     (rewind-stream _test-error-stream)
1841 #?     # }}}
1842     # check output
1843     (check-stream-equal _test-output-stream  ""  "F - test-return-literal-to-float: output should be empty")
1844     (check-next-stream-line-equal _test-error-stream  "fn foo: return: cannot copy literal '0' to float"  "F - test-return-literal-to-float: error message")
1845     # check that stop(1) was called
1846     (check-ints-equal *(edx+4) 2 "F - test-return-literal-to-float: exit status")
1847     # don't restore from ebp
1848     81 0/subop/add %esp 8/imm32
1849     # . epilogue
1850     5d/pop-to-ebp
1851     c3/return
1853 test-convert-return-with-duplicate-values:
1854     # . prologue
1855     55/push-ebp
1856     89/<- %ebp 4/r32/esp
1857     # setup
1858     (clear-stream _test-input-stream)
1859     (clear-stream $_test-input-buffered-file->buffer)
1860     (clear-stream _test-output-stream)
1861     (clear-stream $_test-output-buffered-file->buffer)
1862     #
1863     (write _test-input-stream "fn foo -> _/eax: int, _/ecx: int {\n")
1864     (write _test-input-stream "  var x/eax: int <- copy 0x34\n")
1865     (write _test-input-stream "  return x, x\n")
1866     (write _test-input-stream "}\n")
1867     # convert
1868     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
1869     (flush _test-output-buffered-file)
1870 #?     # dump _test-output-stream {{{
1871 #?     (write 2 "^")
1872 #?     (write-stream 2 _test-output-stream)
1873 #?     (write 2 "$\n")
1874 #?     (rewind-stream _test-output-stream)
1875 #?     # }}}
1876     # check output
1877     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-return-with-duplicate-values/0")
1878     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-return-with-duplicate-values/1")
1879     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-return-with-duplicate-values/2")
1880     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-return-with-duplicate-values/3")
1881     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-return-with-duplicate-values/4")
1882     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-return-with-duplicate-values/5")
1883     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-return-with-duplicate-values/6")
1884     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0x34/imm32"  "F - test-convert-return-with-duplicate-values/7")
1885     (check-next-stream-line-equal _test-output-stream "    8b/-> %eax 0x00000000/r32"  "F - test-convert-return-with-duplicate-values/8")
1886     (check-next-stream-line-equal _test-output-stream "    8b/-> %eax 0x00000001/r32"  "F - test-convert-return-with-duplicate-values/9")
1887     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 4/imm32"  "F - test-convert-return-with-duplicate-values/10")
1888     (check-next-stream-line-equal _test-output-stream "    e9/jump $foo:0x00000001:break/disp32"  "F - test-convert-return-with-duplicate-values/11")
1889     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-return-with-duplicate-values/12")
1890     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-return-with-duplicate-values/13")
1891     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-return-with-duplicate-values/14")
1892     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-return-with-duplicate-values/15")
1893     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-return-with-duplicate-values/16")
1894     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-return-with-duplicate-values/17")
1895     # . epilogue
1896     89/<- %esp 5/r32/ebp
1897     5d/pop-to-ebp
1898     c3/return
1900 test-convert-return-with-duplicate-values-2:
1901     # . prologue
1902     55/push-ebp
1903     89/<- %ebp 4/r32/esp
1904     # setup
1905     (clear-stream _test-input-stream)
1906     (clear-stream $_test-input-buffered-file->buffer)
1907     (clear-stream _test-output-stream)
1908     (clear-stream $_test-output-buffered-file->buffer)
1909     #
1910     (write _test-input-stream "fn foo -> _/eax: int, _/ecx: int {\n")
1911     (write _test-input-stream "  var x/ecx: int <- copy 0x34\n")
1912     (write _test-input-stream "  return x, x\n")
1913     (write _test-input-stream "}\n")
1914     # convert
1915     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
1916     (flush _test-output-buffered-file)
1917 #?     # dump _test-output-stream {{{
1918 #?     (write 2 "^")
1919 #?     (write-stream 2 _test-output-stream)
1920 #?     (write 2 "$\n")
1921 #?     (rewind-stream _test-output-stream)
1922 #?     # }}}
1923     # check output
1924     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-return-with-duplicate-values-2/0")
1925     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-return-with-duplicate-values-2/1")
1926     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-return-with-duplicate-values-2/2")
1927     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-return-with-duplicate-values-2/3")
1928     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-return-with-duplicate-values-2/4")
1929     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-return-with-duplicate-values-2/5")
1930     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-return-with-duplicate-values-2/6")
1931     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0x34/imm32"  "F - test-convert-return-with-duplicate-values-2/7")
1932     (check-next-stream-line-equal _test-output-stream "    8b/-> %ecx 0x00000000/r32"  "F - test-convert-return-with-duplicate-values-2/8")
1933     (check-next-stream-line-equal _test-output-stream "    8b/-> %ecx 0x00000001/r32"  "F - test-convert-return-with-duplicate-values-2/9")
1934     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 4/imm32"  "F - test-convert-return-with-duplicate-values-2/10")
1935     (check-next-stream-line-equal _test-output-stream "    e9/jump $foo:0x00000001:break/disp32"  "F - test-convert-return-with-duplicate-values-2/11")
1936     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-return-with-duplicate-values-2/12")
1937     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-return-with-duplicate-values-2/13")
1938     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-return-with-duplicate-values-2/14")
1939     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-return-with-duplicate-values-2/15")
1940     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-return-with-duplicate-values-2/16")
1941     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-return-with-duplicate-values-2/17")
1942     # . epilogue
1943     89/<- %esp 5/r32/ebp
1944     5d/pop-to-ebp
1945     c3/return
1947 test-stmt-with-unknown-var:
1948     # . prologue
1949     55/push-ebp
1950     89/<- %ebp 4/r32/esp
1951     # setup
1952     (clear-stream _test-input-stream)
1953     (clear-stream $_test-input-buffered-file->buffer)
1954     (clear-stream _test-output-stream)
1955     (clear-stream $_test-output-buffered-file->buffer)
1956     (clear-stream _test-error-stream)
1957     (clear-stream $_test-error-buffered-file->buffer)
1958     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
1959     68/push 0/imm32
1960     68/push 0/imm32
1961     89/<- %edx 4/r32/esp
1962     (tailor-exit-descriptor %edx 0x10)
1963     #
1964     (write _test-input-stream "fn foo {\n")
1965     (write _test-input-stream "  x <- copy 0x34\n")
1966     (write _test-input-stream "}\n")
1967     # convert
1968     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
1969     # registers except esp clobbered at this point
1970     # restore ed
1971     89/<- %edx 4/r32/esp
1972     (flush _test-output-buffered-file)
1973     (flush _test-error-buffered-file)
1974 #?     # dump _test-error-stream {{{
1975 #?     (write 2 "^")
1976 #?     (write-stream 2 _test-error-stream)
1977 #?     (write 2 "$\n")
1978 #?     (rewind-stream _test-error-stream)
1979 #?     # }}}
1980     # check output
1981     (check-stream-equal _test-output-stream  ""  "F - test-stmt-with-unknown-var: output should be empty")
1982     (check-next-stream-line-equal _test-error-stream  "fn foo: unknown variable 'x'"  "F - test-stmt-with-unknown-var: error message")
1983     # check that stop(1) was called
1984     (check-ints-equal *(edx+4) 2 "F - test-stmt-with-unknown-var: exit status")
1985     # don't restore from ebp
1986     81 0/subop/add %esp 8/imm32
1987     # . epilogue
1988     5d/pop-to-ebp
1989     c3/return
1991 test-stmt-with-missing-var-keyword:
1992     # . prologue
1993     55/push-ebp
1994     89/<- %ebp 4/r32/esp
1995     # setup
1996     (clear-stream _test-input-stream)
1997     (clear-stream $_test-input-buffered-file->buffer)
1998     (clear-stream _test-output-stream)
1999     (clear-stream $_test-output-buffered-file->buffer)
2000     (clear-stream _test-error-stream)
2001     (clear-stream $_test-error-buffered-file->buffer)
2002     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
2003     68/push 0/imm32
2004     68/push 0/imm32
2005     89/<- %edx 4/r32/esp
2006     (tailor-exit-descriptor %edx 0x10)
2007     #
2008     (write _test-input-stream "fn foo {\n")
2009     (write _test-input-stream "  x: int\n")
2010     (write _test-input-stream "}\n")
2011     # convert
2012     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
2013     # registers except esp clobbered at this point
2014     # restore ed
2015     89/<- %edx 4/r32/esp
2016     (flush _test-output-buffered-file)
2017     (flush _test-error-buffered-file)
2018 #?     # dump _test-error-stream {{{
2019 #?     (write 2 "^")
2020 #?     (write-stream 2 _test-error-stream)
2021 #?     (write 2 "$\n")
2022 #?     (rewind-stream _test-error-stream)
2023 #?     # }}}
2024     # check output
2025     (check-stream-equal _test-output-stream  ""  "F - test-stmt-with-missing-var-keyword: output should be empty")
2026     (check-next-stream-line-equal _test-error-stream  "fn foo: unexpected ':'; did you forget a 'var'?"  "F - test-stmt-with-missing-var-keyword: error message")
2027     # check that stop(1) was called
2028     (check-ints-equal *(edx+4) 2 "F - test-stmt-with-missing-var-keyword: exit status")
2029     # don't restore from ebp
2030     81 0/subop/add %esp 8/imm32
2031     # . epilogue
2032     5d/pop-to-ebp
2033     c3/return
2035 test-stmt-with-invalid-identifier:
2036     # . prologue
2037     55/push-ebp
2038     89/<- %ebp 4/r32/esp
2039     # setup
2040     (clear-stream _test-input-stream)
2041     (clear-stream $_test-input-buffered-file->buffer)
2042     (clear-stream _test-output-stream)
2043     (clear-stream $_test-output-buffered-file->buffer)
2044     (clear-stream _test-error-stream)
2045     (clear-stream $_test-error-buffered-file->buffer)
2046     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
2047     68/push 0/imm32
2048     68/push 0/imm32
2049     89/<- %edx 4/r32/esp
2050     (tailor-exit-descriptor %edx 0x10)
2051     #
2052     (write _test-input-stream "fn foo {\n")
2053     (write _test-input-stream "  1 <- copy 0x34\n")
2054     (write _test-input-stream "}\n")
2055     # convert
2056     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
2057     # registers except esp clobbered at this point
2058     # restore ed
2059     89/<- %edx 4/r32/esp
2060     (flush _test-output-buffered-file)
2061     (flush _test-error-buffered-file)
2062 #?     # dump _test-error-stream {{{
2063 #?     (write 2 "^")
2064 #?     (write-stream 2 _test-error-stream)
2065 #?     (write 2 "$\n")
2066 #?     (rewind-stream _test-error-stream)
2067 #?     # }}}
2068     # check output
2069     (check-stream-equal _test-output-stream  ""  "F - test-stmt-with-invalid-identifier: output should be empty")
2070     (check-next-stream-line-equal _test-error-stream  "fn foo: invalid identifier '1'"  "F - test-stmt-with-invalid-identifier: error message")
2071     # check that stop(1) was called
2072     (check-ints-equal *(edx+4) 2 "F - test-stmt-with-invalid-identifier: exit status")
2073     # don't restore from ebp
2074     81 0/subop/add %esp 8/imm32
2075     # . epilogue
2076     5d/pop-to-ebp
2077     c3/return
2079 test-stmt-with-deref-var:
2080     # . prologue
2081     55/push-ebp
2082     89/<- %ebp 4/r32/esp
2083     # setup
2084     (clear-stream _test-input-stream)
2085     (clear-stream $_test-input-buffered-file->buffer)
2086     (clear-stream _test-output-stream)
2087     (clear-stream $_test-output-buffered-file->buffer)
2088     (clear-stream _test-error-stream)
2089     (clear-stream $_test-error-buffered-file->buffer)
2090     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
2091     68/push 0/imm32
2092     68/push 0/imm32
2093     89/<- %edx 4/r32/esp
2094     (tailor-exit-descriptor %edx 0x10)
2095     #
2096     (write _test-input-stream "fn foo {\n")
2097     (write _test-input-stream "  *x <- copy 0x34\n")
2098     (write _test-input-stream "}\n")
2099     # convert
2100     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
2101     # registers except esp clobbered at this point
2102     # restore ed
2103     89/<- %edx 4/r32/esp
2104     (flush _test-output-buffered-file)
2105     (flush _test-error-buffered-file)
2106 #?     # dump _test-error-stream {{{
2107 #?     (write 2 "^")
2108 #?     (write-stream 2 _test-error-stream)
2109 #?     (write 2 "$\n")
2110 #?     (rewind-stream _test-error-stream)
2111 #?     # }}}
2112     # check output
2113     (check-stream-equal _test-output-stream  ""  "F - test-stmt-with-deref-var: output should be empty")
2114     (check-next-stream-line-equal _test-error-stream  "fn foo: output '*x' should write to a register, and therefore cannot be dereferenced"  "F - test-stmt-with-deref-var: error message")
2115     # check that stop(1) was called
2116     (check-ints-equal *(edx+4) 2 "F - test-stmt-with-deref-var: exit status")
2117     # don't restore from ebp
2118     81 0/subop/add %esp 8/imm32
2119     # . epilogue
2120     5d/pop-to-ebp
2121     c3/return
2123 test-convert-function-with-literal-arg:
2124     # . prologue
2125     55/push-ebp
2126     89/<- %ebp 4/r32/esp
2127     # setup
2128     (clear-stream _test-input-stream)
2129     (clear-stream $_test-input-buffered-file->buffer)
2130     (clear-stream _test-output-stream)
2131     (clear-stream $_test-output-buffered-file->buffer)
2132     #
2133     (write _test-input-stream "fn foo a: int, b: int -> _/eax: int {\n")
2134     (write _test-input-stream "  var result/eax: int <- copy a\n")
2135     (write _test-input-stream "  result <- add 1\n")
2136     (write _test-input-stream "  return result\n")
2137     (write _test-input-stream "}\n")
2138     # convert
2139     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
2140     (flush _test-output-buffered-file)
2141 #?     # dump _test-output-stream {{{
2142 #?     (write 2 "^")
2143 #?     (write-stream 2 _test-output-stream)
2144 #?     (write 2 "$\n")
2145 #?     (rewind-stream _test-output-stream)
2146 #?     # }}}
2147     # check output
2148     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg/0")
2149     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg/1")
2150     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg/2")
2151     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg/3")
2152     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg/4")
2153     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg/5")
2154     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-function-with-literal-arg/6")
2155     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-with-literal-arg/7")
2156     (check-next-stream-line-equal _test-output-stream "    05/add-to-eax 1/imm32"  "F - test-convert-function-with-literal-arg/8")
2157     (check-next-stream-line-equal _test-output-stream "    8b/-> %eax 0x00000000/r32" "F - test-convert-function-with-literal-arg/9")
2158     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 4/imm32"  "F - test-convert-function-with-literal-arg/10")
2159     (check-next-stream-line-equal _test-output-stream "    e9/jump $foo:0x00000001:break/disp32"  "F - test-convert-function-with-literal-arg/11")
2160     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg/12")
2161     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg/13")
2162     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg/14")
2163     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg/15")
2164     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg/16")
2165     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg/17")
2166     # . epilogue
2167     89/<- %esp 5/r32/ebp
2168     5d/pop-to-ebp
2169     c3/return
2171 test-convert-function-with-literal-arg-2:
2172     # . prologue
2173     55/push-ebp
2174     89/<- %ebp 4/r32/esp
2175     # setup
2176     (clear-stream _test-input-stream)
2177     (clear-stream $_test-input-buffered-file->buffer)
2178     (clear-stream _test-output-stream)
2179     (clear-stream $_test-output-buffered-file->buffer)
2180     #
2181     (write _test-input-stream "fn foo a: int, b: int -> _/ebx: int {\n")
2182     (write _test-input-stream "  var result/ebx: int <- copy a\n")
2183     (write _test-input-stream "  result <- add 1\n")
2184     (write _test-input-stream "  return result\n")
2185     (write _test-input-stream "}\n")
2186     # convert
2187     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
2188     (flush _test-output-buffered-file)
2189 #?     # dump _test-output-stream {{{
2190 #?     (write 2 "^")
2191 #?     (write-stream 2 _test-output-stream)
2192 #?     (write 2 "$\n")
2193 #?     (rewind-stream _test-output-stream)
2194 #?     # }}}
2195     # check output
2196     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg-2/0")
2197     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg-2/1")
2198     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg-2/2")
2199     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg-2/3")
2200     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg-2/4")
2201     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg-2/5")
2202     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ebx"  "F - test-convert-function-with-literal-arg-2/6")
2203     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-with-literal-arg-2/7")
2204     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %ebx 1/imm32"  "F - test-convert-function-with-literal-arg-2/8")
2205     (check-next-stream-line-equal _test-output-stream "    8b/-> %ebx 0x00000003/r32" "F - test-convert-function-with-literal-arg-2/9")
2206     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 4/imm32"  "F - test-convert-function-with-literal-arg-2/10")
2207     (check-next-stream-line-equal _test-output-stream "    e9/jump $foo:0x00000001:break/disp32"  "F - test-convert-function-with-literal-arg-2/11")
2208     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg-2/12")
2209     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg-2/13")
2210     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg-2/14")
2211     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg-2/15")
2212     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg-2/16")
2213     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg-2/17")
2214     # . epilogue
2215     89/<- %esp 5/r32/ebp
2216     5d/pop-to-ebp
2217     c3/return
2219 test-convert-function-call-with-literal-arg:
2220     # . prologue
2221     55/push-ebp
2222     89/<- %ebp 4/r32/esp
2223     # setup
2224     (clear-stream _test-input-stream)
2225     (clear-stream $_test-input-buffered-file->buffer)
2226     (clear-stream _test-output-stream)
2227     (clear-stream $_test-output-buffered-file->buffer)
2228     #
2229     (write _test-input-stream "fn main -> _/ebx: int {\n")
2230     (write _test-input-stream "  var result/eax: int <- do-add 3 4\n")
2231     (write _test-input-stream "  return result\n")
2232     (write _test-input-stream "}\n")
2233     (write _test-input-stream "fn do-add a: int, b: int -> _/eax: int {\n")
2234     (write _test-input-stream "  var result/eax: int <- copy a\n")
2235     (write _test-input-stream "  result <- add b\n")
2236     (write _test-input-stream "  return result\n")
2237     (write _test-input-stream "}\n")
2238     # convert
2239     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
2240     (flush _test-output-buffered-file)
2241 #?     # dump _test-output-stream {{{
2242 #?     (write 2 "^")
2243 #?     (write-stream 2 _test-output-stream)
2244 #?     (write 2 "$\n")
2245 #?     (rewind-stream _test-output-stream)
2246 #?     # }}}
2247     # check output
2248     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call-with-literal-arg/0")
2249     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/1")
2250     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/2")
2251     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/3")
2252     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/4")
2253     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call-with-literal-arg/5")
2254     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-function-call-with-literal-arg/6")
2255     (check-next-stream-line-equal _test-output-stream "    (do-add 3 4)"        "F - test-convert-function-call-with-literal-arg/7")
2256     (check-next-stream-line-equal _test-output-stream "    8b/-> %eax 0x00000003/r32" "F - test-convert-function-call-with-literal-arg/8")
2257     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-convert-function-with-local-var-in-reg/9")
2258     (check-next-stream-line-equal _test-output-stream "    e9/jump $main:0x00000001:break/disp32"  "F - test-convert-function-call-with-literal-arg/10")
2259     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/11")
2260     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-literal-arg/12")
2261     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/13")
2262     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/14")
2263     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/15")
2264     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/16")
2265     (check-next-stream-line-equal _test-output-stream "do-add:"                 "F - test-convert-function-call-with-literal-arg/17")
2266     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/18")
2267     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/19")
2268     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/20")
2269     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/21")
2270     (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:loop:"  "F - test-convert-function-call-with-literal-arg/22")
2271     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-function-call-with-literal-arg/23")
2272     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-call-with-literal-arg/24")
2273     (check-next-stream-line-equal _test-output-stream "    03/add *(ebp+0x0000000c) 0x00000000/r32"  "F - test-convert-function-call-with-literal-arg/25")
2274     (check-next-stream-line-equal _test-output-stream "    8b/-> %eax 0x00000000/r32" "F - test-convert-function-call-with-literal-arg/26")
2275     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 4/imm32"  "F - test-convert-function-call-with-literal-arg/27")
2276     (check-next-stream-line-equal _test-output-stream "    e9/jump $do-add:0x00000002:break/disp32"  "F - test-convert-function-call-with-literal-arg/28")
2277     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/29")
2278     (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:break:"  "F - test-convert-function-call-with-literal-arg/30")
2279     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/31")
2280     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/32")
2281     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/33")
2282     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/34")
2283     # . epilogue
2284     89/<- %esp 5/r32/ebp
2285     5d/pop-to-ebp
2286     c3/return
2288 test-convert-function-call-with-literal-string-arg:
2289     # . prologue
2290     55/push-ebp
2291     89/<- %ebp 4/r32/esp
2292     # setup
2293     (clear-stream _test-input-stream)
2294     (clear-stream $_test-input-buffered-file->buffer)
2295     (clear-stream _test-output-stream)
2296     (clear-stream $_test-output-buffered-file->buffer)
2297     #
2298     (write _test-input-stream "fn foo {\n")
2299     (write _test-input-stream "  string-func \"abc\"\n")
2300     (write _test-input-stream "}\n")
2301     (write _test-input-stream "sig string-func in: (addr array byte)\n")
2302     # convert
2303     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
2304     # no errors
2305     # not bothering checking output
2306     # . epilogue
2307     89/<- %esp 5/r32/ebp
2308     5d/pop-to-ebp
2309     c3/return
2311 test-convert-function-call-with-literal-string-arg-and-type-parameter-in-signature:
2312     # . prologue
2313     55/push-ebp
2314     89/<- %ebp 4/r32/esp
2315     # setup
2316     (clear-stream _test-input-stream)
2317     (clear-stream $_test-input-buffered-file->buffer)
2318     (clear-stream _test-output-stream)
2319     (clear-stream $_test-output-buffered-file->buffer)
2320     #
2321     (write _test-input-stream "fn foo {\n")
2322     (write _test-input-stream "  string-func \"abc\"\n")
2323     (write _test-input-stream "}\n")
2324     (write _test-input-stream "sig string-func in: (addr array _)\n")
2325     # convert
2326     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
2327     # no errors
2328     # not bothering checking output
2329     # . epilogue
2330     89/<- %esp 5/r32/ebp
2331     5d/pop-to-ebp
2332     c3/return
2334 test-convert-function-call-with-null-addr:
2335     # . prologue
2336     55/push-ebp
2337     89/<- %ebp 4/r32/esp
2338     # setup
2339     (clear-stream _test-input-stream)
2340     (clear-stream $_test-input-buffered-file->buffer)
2341     (clear-stream _test-output-stream)
2342     (clear-stream $_test-output-buffered-file->buffer)
2343     #
2344     (write _test-input-stream "fn foo {\n")
2345     (write _test-input-stream "  bar 0\n")
2346     (write _test-input-stream "}\n")
2347     (write _test-input-stream "sig bar in: (addr int)\n")
2348     # convert
2349     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
2350     # no errors
2351     # not bothering checking output
2352     # . epilogue
2353     89/<- %esp 5/r32/ebp
2354     5d/pop-to-ebp
2355     c3/return
2357 test-convert-function-call-with-signature:
2358     # . prologue
2359     55/push-ebp
2360     89/<- %ebp 4/r32/esp
2361     # setup
2362     (clear-stream _test-input-stream)
2363     (clear-stream $_test-input-buffered-file->buffer)
2364     (clear-stream _test-output-stream)
2365     (clear-stream $_test-output-buffered-file->buffer)
2366     #
2367     (write _test-input-stream "fn main -> _/ebx: int {\n")
2368     (write _test-input-stream "  var result/eax: int <- do-add 3 4\n")
2369     (write _test-input-stream "  return result\n")
2370     (write _test-input-stream "}\n")
2371     (write _test-input-stream "sig do-add a: int, b: int -> _/eax: int\n")
2372     # convert
2373     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
2374     (flush _test-output-buffered-file)
2375 #?     # dump _test-output-stream {{{
2376 #?     (write 2 "^")
2377 #?     (write-stream 2 _test-output-stream)
2378 #?     (write 2 "$\n")
2379 #?     (rewind-stream _test-output-stream)
2380 #?     # }}}
2381     # check output
2382     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call-with-signature/0")
2383     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-signature/1")
2384     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-signature/2")
2385     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-signature/3")
2386     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-signature/4")
2387     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call-with-signature/5")
2388     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-function-call-with-literal-arg/6")
2389     (check-next-stream-line-equal _test-output-stream "    (do-add 3 4)"        "F - test-convert-function-call-with-signature/6")
2390     (check-next-stream-line-equal _test-output-stream "    8b/-> %eax 0x00000003/r32" "F - test-convert-function-call-with-literal-arg/8")
2391     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-convert-function-with-local-var-in-reg/9")
2392     (check-next-stream-line-equal _test-output-stream "    e9/jump $main:0x00000001:break/disp32"  "F - test-convert-function-call-with-literal-arg/10")
2393     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-signature/7")
2394     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-signature/8")
2395     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-signature/9")
2396     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-signature/10")
2397     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-signature/11")
2398     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-signature/12")
2399     # . epilogue
2400     89/<- %esp 5/r32/ebp
2401     5d/pop-to-ebp
2402     c3/return
2404 test-convert-function-with-local-var-in-mem:
2405     # . prologue
2406     55/push-ebp
2407     89/<- %ebp 4/r32/esp
2408     # setup
2409     (clear-stream _test-input-stream)
2410     (clear-stream $_test-input-buffered-file->buffer)
2411     (clear-stream _test-output-stream)
2412     (clear-stream $_test-output-buffered-file->buffer)
2413     #
2414     (write _test-input-stream "fn foo {\n")
2415     (write _test-input-stream "  var x: int\n")
2416     (write _test-input-stream "  increment x\n")
2417     (write _test-input-stream "}\n")
2418     # convert
2419     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
2420     (flush _test-output-buffered-file)
2421 #?     # dump _test-output-stream {{{
2422 #?     (write 2 "^")
2423 #?     (write-stream 2 _test-output-stream)
2424 #?     (write 2 "$\n")
2425 #?     (rewind-stream _test-output-stream)
2426 #?     # }}}
2427     # check output
2428     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-mem/0")
2429     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-mem/1")
2430     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-mem/2")
2431     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-mem/3")
2432     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-mem/4")
2433     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-mem/5")
2434     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-in-mem/6")
2435     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-mem/7")
2436     (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")
2437     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-mem/9")
2438     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-mem/10")
2439     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-mem/11")
2440     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-mem/12")
2441     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-mem/13")
2442     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-mem/14")
2443     # . epilogue
2444     89/<- %esp 5/r32/ebp
2445     5d/pop-to-ebp
2446     c3/return
2448 test-convert-invalid-literal:
2449     # . prologue
2450     55/push-ebp
2451     89/<- %ebp 4/r32/esp
2452     # setup
2453     (clear-stream _test-input-stream)
2454     (clear-stream $_test-input-buffered-file->buffer)
2455     (clear-stream _test-output-stream)
2456     (clear-stream $_test-output-buffered-file->buffer)
2457     (clear-stream _test-error-stream)
2458     (clear-stream $_test-error-buffered-file->buffer)
2459     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
2460     68/push 0/imm32
2461     68/push 0/imm32
2462     89/<- %edx 4/r32/esp
2463     (tailor-exit-descriptor %edx 0x10)
2464     #
2465     (write _test-input-stream "fn foo {\n")
2466     (write _test-input-stream "  increment 1n\n")
2467     (write _test-input-stream "}\n")
2468     # convert
2469     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
2470     # registers except esp clobbered at this point
2471     # restore ed
2472     89/<- %edx 4/r32/esp
2473     (flush _test-output-buffered-file)
2474     (flush _test-error-buffered-file)
2475 #?     # dump _test-error-stream {{{
2476 #?     (write 2 "^")
2477 #?     (write-stream 2 _test-error-stream)
2478 #?     (write 2 "$\n")
2479 #?     (rewind-stream _test-error-stream)
2480 #?     # }}}
2481     # check output
2482     (check-stream-equal _test-output-stream  ""  "F - test-convert-invalid-literal: output should be empty")
2483     (check-next-stream-line-equal _test-error-stream  "fn foo: variable '1n' cannot begin with a digit (or do you have a typo in a number?)"  "F - test-convert-invalid-literal: error message")
2484     # check that stop(1) was called
2485     (check-ints-equal *(edx+4) 2 "F - test-convert-invalid-literal: exit status")
2486     # don't restore from ebp
2487     81 0/subop/add %esp 8/imm32
2488     # . epilogue
2489     5d/pop-to-ebp
2490     c3/return
2492 test-convert-valid-literal-with-metadata:
2493     # . prologue
2494     55/push-ebp
2495     89/<- %ebp 4/r32/esp
2496     # setup
2497     (clear-stream _test-input-stream)
2498     (clear-stream $_test-input-buffered-file->buffer)
2499     (clear-stream _test-output-stream)
2500     (clear-stream $_test-output-buffered-file->buffer)
2501     #
2502     (write _test-input-stream "fn foo {\n")
2503     (write _test-input-stream "  var x/eax: int <- copy 1/abc\n")
2504     (write _test-input-stream "}\n")
2505     # convert
2506     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
2507     (flush _test-output-buffered-file)
2508 #?     # dump _test-output-stream {{{
2509 #?     (write 2 "^")
2510 #?     (write-stream 2 _test-output-stream)
2511 #?     (write 2 "$\n")
2512 #?     (rewind-stream _test-output-stream)
2513 #?     # }}}
2514     # no errors
2515     # . epilogue
2516     89/<- %esp 5/r32/ebp
2517     5d/pop-to-ebp
2518     c3/return
2520 test-local-var-in-mem-has-no-initializer:
2521     # . prologue
2522     55/push-ebp
2523     89/<- %ebp 4/r32/esp
2524     # setup
2525     (clear-stream _test-input-stream)
2526     (clear-stream $_test-input-buffered-file->buffer)
2527     (clear-stream _test-output-stream)
2528     (clear-stream $_test-output-buffered-file->buffer)
2529     (clear-stream _test-error-stream)
2530     (clear-stream $_test-error-buffered-file->buffer)
2531     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
2532     68/push 0/imm32
2533     68/push 0/imm32
2534     89/<- %edx 4/r32/esp
2535     (tailor-exit-descriptor %edx 0x10)
2536     #
2537     (write _test-input-stream "fn foo {\n")
2538     (write _test-input-stream "  var x: int <- copy 0\n")
2539     (write _test-input-stream "  increment x\n")
2540     (write _test-input-stream "}\n")
2541     # convert
2542     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
2543     # registers except esp clobbered at this point
2544     # restore ed
2545     89/<- %edx 4/r32/esp
2546     (flush _test-output-buffered-file)
2547     (flush _test-error-buffered-file)
2548 #?     # dump _test-error-stream {{{
2549 #?     (write 2 "^")
2550 #?     (write-stream 2 _test-error-stream)
2551 #?     (write 2 "$\n")
2552 #?     (rewind-stream _test-error-stream)
2553 #?     # }}}
2554     # check output
2555     (check-stream-equal _test-output-stream  ""  "F - test-var-in-mem-has-no-initializer: output should be empty")
2556     (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")
2557     # check that stop(1) was called
2558     (check-ints-equal *(edx+4) 2 "F - test-var-in-mem-has-no-initializer: exit status")
2559     # don't restore from ebp
2560     81 0/subop/add %esp 8/imm32
2561     # . epilogue
2562     5d/pop-to-ebp
2563     c3/return
2565 test-convert-function-with-local-var-with-compound-type-in-mem:
2566     # . prologue
2567     55/push-ebp
2568     89/<- %ebp 4/r32/esp
2569     # setup
2570     (clear-stream _test-input-stream)
2571     (clear-stream $_test-input-buffered-file->buffer)
2572     (clear-stream _test-output-stream)
2573     (clear-stream $_test-output-buffered-file->buffer)
2574     #
2575     (write _test-input-stream "fn foo {\n")
2576     (write _test-input-stream "  var x: (addr int)\n")
2577     (write _test-input-stream "  copy-to x, 0\n")
2578     (write _test-input-stream "}\n")
2579     # convert
2580     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
2581     (flush _test-output-buffered-file)
2582 #?     # dump _test-output-stream {{{
2583 #?     (write 2 "^")
2584 #?     (write-stream 2 _test-output-stream)
2585 #?     (write 2 "$\n")
2586 #?     (rewind-stream _test-output-stream)
2587 #?     # }}}
2588     # check output
2589     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-compound-type-in-mem/0")
2590     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/1")
2591     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-compound-type-in-mem/2")
2592     (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")
2593     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/4")
2594     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-compound-type-in-mem/5")
2595     (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")
2596     (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")
2597     (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")
2598     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/9")
2599     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/10")
2600     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/11")
2601     (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")
2602     (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")
2603     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-compound-type-in-mem/14")
2604     # . epilogue
2605     89/<- %esp 5/r32/ebp
2606     5d/pop-to-ebp
2607     c3/return
2609 test-convert-function-with-local-var-in-reg:
2610     # . prologue
2611     55/push-ebp
2612     89/<- %ebp 4/r32/esp
2613     # setup
2614     (clear-stream _test-input-stream)
2615     (clear-stream $_test-input-buffered-file->buffer)
2616     (clear-stream _test-output-stream)
2617     (clear-stream $_test-output-buffered-file->buffer)
2618     #
2619     (write _test-input-stream "fn foo {\n")
2620     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
2621     (write _test-input-stream "  x <- increment\n")
2622     (write _test-input-stream "}\n")
2623     # convert
2624     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
2625     (flush _test-output-buffered-file)
2626 #?     # dump _test-output-stream {{{
2627 #?     (write 2 "^")
2628 #?     (write-stream 2 _test-output-stream)
2629 #?     (write 2 "$\n")
2630 #?     (rewind-stream _test-output-stream)
2631 #?     # }}}
2632     # check output
2633     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-reg/0")
2634     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-reg/1")
2635     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-reg/2")
2636     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-reg/3")
2637     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-reg/4")
2638     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-reg/5")
2639     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-in-reg/6")
2640     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-convert-function-with-local-var-in-reg/7")
2641     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-local-var-in-reg/8")
2642     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-in-reg/9")
2643     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-reg/10")
2644     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-reg/11")
2645     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-reg/12")
2646     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-reg/13")
2647     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-reg/14")
2648     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-reg/15")
2649     # . epilogue
2650     89/<- %esp 5/r32/ebp
2651     5d/pop-to-ebp
2652     c3/return
2654 test-convert-function-with-local-var-in-same-reg:
2655     # . prologue
2656     55/push-ebp
2657     89/<- %ebp 4/r32/esp
2658     # setup
2659     (clear-stream _test-input-stream)
2660     (clear-stream $_test-input-buffered-file->buffer)
2661     (clear-stream _test-output-stream)
2662     (clear-stream $_test-output-buffered-file->buffer)
2663     #
2664     (write _test-input-stream "fn foo {\n")
2665     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
2666     (write _test-input-stream "  var y/ecx: int <- copy x\n")
2667     (write _test-input-stream "}\n")
2668     # convert
2669     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
2670     (flush _test-output-buffered-file)
2671 #?     # dump _test-output-stream {{{
2672 #?     (write 2 "^")
2673 #?     (write-stream 2 _test-output-stream)
2674 #?     (write 2 "$\n")
2675 #?     (rewind-stream _test-output-stream)
2676 #?     # }}}
2677     # check output
2678     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-same-reg/0")
2679     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-same-reg/1")
2680     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-same-reg/2")
2681     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-same-reg/3")
2682     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-same-reg/4")
2683     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-same-reg/5")
2684     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-in-same-reg/6")
2685     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-convert-function-with-local-var-in-same-reg/7")
2686     # optimization: skip the second copy
2687     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-in-same-reg/8")
2688     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-same-reg/9")
2689     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-same-reg/10")
2690     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-same-reg/11")
2691     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-same-reg/12")
2692     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-same-reg/13")
2693     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-same-reg/14")
2694     # . epilogue
2695     89/<- %esp 5/r32/ebp
2696     5d/pop-to-ebp
2697     c3/return
2699 test-convert-function-with-local-var-in-same-reg-dereferenced:
2700     # . prologue
2701     55/push-ebp
2702     89/<- %ebp 4/r32/esp
2703     # setup
2704     (clear-stream _test-input-stream)
2705     (clear-stream $_test-input-buffered-file->buffer)
2706     (clear-stream _test-output-stream)
2707     (clear-stream $_test-output-buffered-file->buffer)
2708     #
2709     (write _test-input-stream "fn foo {\n")
2710     (write _test-input-stream "  var x/ecx: (addr int) <- copy 0\n")
2711     (write _test-input-stream "  var y/ecx: int <- copy *x\n")
2712     (write _test-input-stream "}\n")
2713     # convert
2714     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
2715     (flush _test-output-buffered-file)
2716 #?     # dump _test-output-stream {{{
2717 #?     (write 2 "^")
2718 #?     (write-stream 2 _test-output-stream)
2719 #?     (write 2 "$\n")
2720 #?     (rewind-stream _test-output-stream)
2721 #?     # }}}
2722     # check output
2723     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-same-reg-dereferenced/0")
2724     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-same-reg-dereferenced/1")
2725     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-same-reg-dereferenced/2")
2726     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-same-reg-dereferenced/3")
2727     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-same-reg-dereferenced/4")
2728     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-same-reg-dereferenced/5")
2729     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-in-same-reg-dereferenced/6")
2730     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-local-var-in-same-reg-dereferenced/7")
2731     (check-next-stream-line-equal _test-output-stream "    8b/-> *ecx 0x00000001/r32"  "F - test-convert-function-with-local-var-in-same-reg-dereferenced/8")  # don't optimize this away
2732     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-in-same-reg-dereferenced/9")
2733     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-same-reg-dereferenced/10")
2734     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-same-reg-dereferenced/11")
2735     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-same-reg-dereferenced/12")
2736     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-same-reg-dereferenced/13")
2737     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-same-reg-dereferenced/14")
2738     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-same-reg-dereferenced/15")
2739     # . epilogue
2740     89/<- %esp 5/r32/ebp
2741     5d/pop-to-ebp
2742     c3/return
2744 test-float-var-in-wrong-register:
2745     # . prologue
2746     55/push-ebp
2747     89/<- %ebp 4/r32/esp
2748     # setup
2749     (clear-stream _test-input-stream)
2750     (clear-stream $_test-input-buffered-file->buffer)
2751     (clear-stream _test-output-stream)
2752     (clear-stream $_test-output-buffered-file->buffer)
2753     (clear-stream _test-error-stream)
2754     (clear-stream $_test-error-buffered-file->buffer)
2755     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
2756     68/push 0/imm32
2757     68/push 0/imm32
2758     89/<- %edx 4/r32/esp
2759     (tailor-exit-descriptor %edx 0x10)
2760     #
2761     (write _test-input-stream "fn foo {\n")
2762     (write _test-input-stream "  var x/eax: int <- copy 0\n")
2763     (write _test-input-stream "  var y/eax: float <- convert x\n")
2764     (write _test-input-stream "}\n")
2765     # convert
2766     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
2767     # registers except esp clobbered at this point
2768     # restore ed
2769     89/<- %edx 4/r32/esp
2770     (flush _test-output-buffered-file)
2771     (flush _test-error-buffered-file)
2772 #?     # dump _test-error-stream {{{
2773 #?     (write 2 "^")
2774 #?     (write-stream 2 _test-error-stream)
2775 #?     (write 2 "$\n")
2776 #?     (rewind-stream _test-error-stream)
2777 #?     # }}}
2778     # check output
2779     (check-stream-equal _test-output-stream  ""  "F - test-float-var-in-wrong-register: output should be empty")
2780     (check-next-stream-line-equal _test-error-stream  "fn foo: float var 'y' should be in a floating-point register"  "F - test-float-var-in-wrong-register: error message")
2781     # check that stop(1) was called
2782     (check-ints-equal *(edx+4) 2 "F - test-float-var-in-wrong-register: exit status")
2783     # don't restore from ebp
2784     81 0/subop/add %esp 8/imm32
2785     # . epilogue
2786     5d/pop-to-ebp
2787     c3/return
2789 test-non-float-var-in-wrong-register:
2790     # . prologue
2791     55/push-ebp
2792     89/<- %ebp 4/r32/esp
2793     # setup
2794     (clear-stream _test-input-stream)
2795     (clear-stream $_test-input-buffered-file->buffer)
2796     (clear-stream _test-output-stream)
2797     (clear-stream $_test-output-buffered-file->buffer)
2798     (clear-stream _test-error-stream)
2799     (clear-stream $_test-error-buffered-file->buffer)
2800     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
2801     68/push 0/imm32
2802     68/push 0/imm32
2803     89/<- %edx 4/r32/esp
2804     (tailor-exit-descriptor %edx 0x10)
2805     #
2806     (write _test-input-stream "fn foo {\n")
2807     (write _test-input-stream "  var x/xmm5: int <- copy 0\n")
2808     (write _test-input-stream "}\n")
2809     # convert
2810     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
2811     # registers except esp clobbered at this point
2812     # restore ed
2813     89/<- %edx 4/r32/esp
2814     (flush _test-output-buffered-file)
2815     (flush _test-error-buffered-file)
2816 #?     # dump _test-error-stream {{{
2817 #?     (write 2 "^")
2818 #?     (write-stream 2 _test-error-stream)
2819 #?     (write 2 "$\n")
2820 #?     (rewind-stream _test-error-stream)
2821 #?     # }}}
2822     # check output
2823     (check-stream-equal _test-output-stream  ""  "F - test-non-float-var-in-wrong-register: output should be empty")
2824     (check-next-stream-line-equal _test-error-stream  "fn foo: non-float var 'x' should be in an integer register"  "F - test-non-float-var-in-wrong-register: error message")
2825     # check that stop(1) was called
2826     (check-ints-equal *(edx+4) 2 "F - test-non-float-var-in-wrong-register: exit status")
2827     # don't restore from ebp
2828     81 0/subop/add %esp 8/imm32
2829     # . epilogue
2830     5d/pop-to-ebp
2831     c3/return
2833 test-convert-function-with-allocate:
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 "  var x/ecx: (addr handle int) <- copy 0\n")
2845     (write _test-input-stream "  allocate x\n")
2846     (write _test-input-stream "}\n")
2847     # convert
2848     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
2849     (flush _test-output-buffered-file)
2850 #?     # dump _test-output-stream {{{
2851 #?     (write 2 "^")
2852 #?     (write-stream 2 _test-output-stream)
2853 #?     (write 2 "$\n")
2854 #?     (rewind-stream _test-output-stream)
2855 #?     # }}}
2856     # check output
2857     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-allocate/0")
2858     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-allocate/1")
2859     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-allocate/2")
2860     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-allocate/3")
2861     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-allocate/4")
2862     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-allocate/5")
2863     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-allocate/6")
2864     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-allocate/7")
2865     (check-next-stream-line-equal _test-output-stream "    (allocate Heap 0x00000004 %ecx)"  "F - test-convert-function-with-allocate/8")  # 4 = size-of(int)
2866     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-allocate/9")
2867     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-allocate/10")
2868     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-allocate/11")
2869     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-allocate/12")
2870     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-allocate/13")
2871     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-allocate/14")
2872     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-allocate/15")
2873     # . epilogue
2874     89/<- %esp 5/r32/ebp
2875     5d/pop-to-ebp
2876     c3/return
2878 test-initializer-in-hex:
2879     # . prologue
2880     55/push-ebp
2881     89/<- %ebp 4/r32/esp
2882     # setup
2883     (clear-stream _test-input-stream)
2884     (clear-stream $_test-input-buffered-file->buffer)
2885     (clear-stream _test-output-stream)
2886     (clear-stream $_test-output-buffered-file->buffer)
2887     (clear-stream _test-error-stream)
2888     (clear-stream $_test-error-buffered-file->buffer)
2889     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
2890     68/push 0/imm32
2891     68/push 0/imm32
2892     89/<- %edx 4/r32/esp
2893     (tailor-exit-descriptor %edx 0x10)
2894     #
2895     (write _test-input-stream "fn foo {\n")
2896     (write _test-input-stream "  var x/ecx: int <- copy 10\n")
2897     (write _test-input-stream "}\n")
2898     # convert
2899     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
2900     # registers except esp clobbered at this point
2901     # restore ed
2902     89/<- %edx 4/r32/esp
2903     (flush _test-output-buffered-file)
2904     (flush _test-error-buffered-file)
2905 #?     # dump _test-error-stream {{{
2906 #?     (write 2 "^")
2907 #?     (write-stream 2 _test-error-stream)
2908 #?     (write 2 "$\n")
2909 #?     (rewind-stream _test-error-stream)
2910 #?     # }}}
2911     # check output
2912     (check-stream-equal _test-output-stream  ""  "F - test-initializer-in-hex: output should be empty")
2913     (check-next-stream-line-equal _test-error-stream  "literal integers are always hex in Mu; start '10' with a '0x' to be unambiguous, converting it to hexadecimal as necessary."  "F - test-initializer-in-hex: error message")
2914     # check that stop(1) was called
2915     (check-ints-equal *(edx+4) 2 "F - test-initializer-in-hex: exit status")
2916     # don't restore from ebp
2917     81 0/subop/add %esp 8/imm32
2918     # . epilogue
2919     5d/pop-to-ebp
2920     c3/return
2922 test-convert-function-with-second-local-var-in-same-reg:
2923     # . prologue
2924     55/push-ebp
2925     89/<- %ebp 4/r32/esp
2926     # setup
2927     (clear-stream _test-input-stream)
2928     (clear-stream $_test-input-buffered-file->buffer)
2929     (clear-stream _test-output-stream)
2930     (clear-stream $_test-output-buffered-file->buffer)
2931     #
2932     (write _test-input-stream "fn foo {\n")
2933     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
2934     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
2935     (write _test-input-stream "  y <- increment\n")
2936     (write _test-input-stream "}\n")
2937     # convert
2938     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
2939     (flush _test-output-buffered-file)
2940 #?     # dump _test-output-stream {{{
2941 #?     (write 2 "^")
2942 #?     (write-stream 2 _test-output-stream)
2943 #?     (write 2 "$\n")
2944 #?     (rewind-stream _test-output-stream)
2945 #?     # }}}
2946     # check output
2947     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-second-local-var-in-same-reg/0")
2948     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-second-local-var-in-same-reg/1")
2949     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-second-local-var-in-same-reg/2")
2950     (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")
2951     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-second-local-var-in-same-reg/4")
2952     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-second-local-var-in-same-reg/5")
2953     (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")
2954     (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")
2955     (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")
2956     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-second-local-var-in-same-reg/9")
2957     (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")
2958     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-second-local-var-in-same-reg/11")
2959     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-second-local-var-in-same-reg/12")
2960     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-second-local-var-in-same-reg/13")
2961     (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")
2962     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-second-local-var-in-same-reg/15")
2963     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-second-local-var-in-same-reg/16")
2964     # . epilogue
2965     89/<- %esp 5/r32/ebp
2966     5d/pop-to-ebp
2967     c3/return
2969 test-read-clobbered-reg-var:
2970     # . prologue
2971     55/push-ebp
2972     89/<- %ebp 4/r32/esp
2973     # setup
2974     (clear-stream _test-input-stream)
2975     (clear-stream $_test-input-buffered-file->buffer)
2976     (clear-stream _test-output-stream)
2977     (clear-stream $_test-output-buffered-file->buffer)
2978     (clear-stream _test-error-stream)
2979     (clear-stream $_test-error-buffered-file->buffer)
2980     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)  # bytes of args in call to convert-mu
2981     68/push 0/imm32
2982     68/push 0/imm32
2983     89/<- %edx 4/r32/esp
2984     (tailor-exit-descriptor %edx 0x10)
2985     #
2986     (write _test-input-stream "fn foo {\n")
2987     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
2988     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
2989     (write _test-input-stream "  x <- increment\n")
2990     (write _test-input-stream "}\n")
2991     # convert
2992     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
2993     # registers except esp clobbered at this point
2994     # restore ed
2995     89/<- %edx 4/r32/esp
2996     (flush _test-output-buffered-file)
2997     (flush _test-error-buffered-file)
2998 #?     # dump _test-error-stream {{{
2999 #?     (write 2 "^")
3000 #?     (write-stream 2 _test-error-stream)
3001 #?     (write 2 "$\n")
3002 #?     (rewind-stream _test-error-stream)
3003 #?     # }}}
3004     # check output
3005     (check-stream-equal _test-output-stream  ""  "F - test-read-clobbered-reg-var: output should be empty")
3006     (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")
3007     # check that stop(1) was called
3008     (check-ints-equal *(edx+4) 2 "F - test-read-clobbered-reg-var: exit status")
3009     # don't restore from ebp
3010     81 0/subop/add %esp 8/imm32
3011     # . epilogue
3012     5d/pop-to-ebp
3013     c3/return
3015 test-overlapping-int-fp-registers:
3016     # . prologue
3017     55/push-ebp
3018     89/<- %ebp 4/r32/esp
3019     # setup
3020     (clear-stream _test-input-stream)
3021     (clear-stream $_test-input-buffered-file->buffer)
3022     (clear-stream _test-output-stream)
3023     (clear-stream $_test-output-buffered-file->buffer)
3024     (clear-stream _test-error-stream)
3025     (clear-stream $_test-error-buffered-file->buffer)
3026     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)  # bytes of args in call to convert-mu
3027     68/push 0/imm32
3028     68/push 0/imm32
3029     89/<- %edx 4/r32/esp
3030     (tailor-exit-descriptor %edx 0x10)
3031     #
3032     (write _test-input-stream "fn foo {\n")
3033     (write _test-input-stream "  var x/eax: int <- copy 3\n")
3034     (write _test-input-stream "  var y/xmm0: float <- convert x\n")
3035     (write _test-input-stream "  x <- increment\n")
3036     (write _test-input-stream "}\n")
3037     # convert
3038     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
3039     # registers except esp clobbered at this point
3040     # restore ed
3041     89/<- %edx 4/r32/esp
3042     (flush _test-output-buffered-file)
3043     (flush _test-error-buffered-file)
3044 #?     # dump _test-error-stream {{{
3045 #?     (write 2 "^")
3046 #?     (write-stream 2 _test-error-stream)
3047 #?     (write 2 "$\n")
3048 #?     (rewind-stream _test-error-stream)
3049 #?     # }}}
3050     # no errors
3051     (check-next-stream-line-equal _test-error-stream  ""  "F - test-overlapping-int-fp-registers: error message")
3052     # don't bother checking the generated code
3053     # don't restore from ebp
3054     81 0/subop/add %esp 8/imm32
3055     # . epilogue
3056     5d/pop-to-ebp
3057     c3/return
3059 test-convert-function-call:
3060     # . prologue
3061     55/push-ebp
3062     89/<- %ebp 4/r32/esp
3063     # setup
3064     (clear-stream _test-input-stream)
3065     (clear-stream $_test-input-buffered-file->buffer)
3066     (clear-stream _test-output-stream)
3067     (clear-stream $_test-output-buffered-file->buffer)
3068     #
3069     (write _test-input-stream "fn main -> _/ebx: int {\n")
3070     (write _test-input-stream "  var result/ebx: int <- foo\n")
3071     (write _test-input-stream "  return result\n")
3072     (write _test-input-stream "}\n")
3073     (write _test-input-stream "fn foo -> _/ebx: int {\n")
3074     (write _test-input-stream "  var result/ebx: int <- copy 3\n")
3075     (write _test-input-stream "  return result\n")
3076     (write _test-input-stream "}\n")
3077     # convert
3078     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
3079     (flush _test-output-buffered-file)
3080 #?     # dump _test-output-stream {{{
3081 #?     (write 2 "^")
3082 #?     (write-stream 2 _test-output-stream)
3083 #?     (write 2 "$\n")
3084 #?     (rewind-stream _test-output-stream)
3085 #?     # }}}
3086     # check output
3087     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call/0")
3088     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call/1")
3089     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call/2")
3090     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call/3")
3091     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call/4")
3092     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call/5")
3093     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ebx"  "F - test-convert-function-call-with-literal-arg/6")
3094     (check-next-stream-line-equal _test-output-stream "    (foo)"               "F - test-convert-function-call/6")
3095     (check-next-stream-line-equal _test-output-stream "    8b/-> %ebx 0x00000003/r32" "F - test-convert-function-call-with-literal-arg/8")
3096     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 4/imm32"  "F - test-convert-function-call-with-literal-arg/27")
3097     (check-next-stream-line-equal _test-output-stream "    e9/jump $main:0x00000001:break/disp32"  "F - test-convert-function-call-with-literal-arg/10")
3098     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call/7")
3099     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call/8")
3100     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call/9")
3101     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call/10")
3102     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call/11")
3103     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call/12")
3104     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call/13")
3105     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call/14")
3106     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call/15")
3107     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call/16")
3108     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call/17")
3109     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"  "F - test-convert-function-call/18")
3110     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ebx"  "F - test-convert-function-call-with-literal-arg/6")
3111     (check-next-stream-line-equal _test-output-stream "    bb/copy-to-ebx 3/imm32"  "F - test-convert-function-call/19")
3112     (check-next-stream-line-equal _test-output-stream "    8b/-> %ebx 0x00000003/r32" "F - test-convert-function-call-with-literal-arg/8")
3113     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 4/imm32"  "F - test-convert-function-call-with-literal-arg/27")
3114     (check-next-stream-line-equal _test-output-stream "    e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-call-with-literal-arg/10")
3115     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call/20")
3116     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-call/21")
3117     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call/22")
3118     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call/23")
3119     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call/24")
3120     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call/25")
3121     # . epilogue
3122     89/<- %esp 5/r32/ebp
3123     5d/pop-to-ebp
3124     c3/return
3126 test-convert-function-call-with-inout-with-compound-type:
3127     # . prologue
3128     55/push-ebp
3129     89/<- %ebp 4/r32/esp
3130     # setup
3131     (clear-stream _test-input-stream)
3132     (clear-stream $_test-input-buffered-file->buffer)
3133     (clear-stream _test-output-stream)
3134     (clear-stream $_test-output-buffered-file->buffer)
3135     #
3136     (write _test-input-stream "fn f {\n")
3137     (write _test-input-stream "  var x: (addr int)\n")
3138     (write _test-input-stream "  g x\n")
3139     (write _test-input-stream "}\n")
3140     (write _test-input-stream "fn g a: (addr int) {\n")
3141     (write _test-input-stream "}\n")
3142     # convert
3143     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
3144     (flush _test-output-buffered-file)
3145 #?     # dump _test-output-stream {{{
3146 #?     (write 2 "^")
3147 #?     (write-stream 2 _test-output-stream)
3148 #?     (write 2 "$\n")
3149 #?     (rewind-stream _test-output-stream)
3150 #?     # }}}
3151     # check output
3152     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-inout-with-compound-type/0")
3153     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-inout-with-compound-type/1")
3154     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-inout-with-compound-type/2")
3155     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-inout-with-compound-type/3")
3156     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-inout-with-compound-type/4")
3157     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-inout-with-compound-type/5")
3158     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-inout-with-compound-type/6")
3159     (check-next-stream-line-equal _test-output-stream "    (g *(ebp+0xfffffffc))"  "F - test-convert-function-call-with-inout-with-compound-type/7")
3160     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-call-with-inout-with-compound-type/8")
3161     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-inout-with-compound-type/9")
3162     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-inout-with-compound-type/10")
3163     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-inout-with-compound-type/11")
3164     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-inout-with-compound-type/12")
3165     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-inout-with-compound-type/13")
3166     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-inout-with-compound-type/14")
3167     (check-next-stream-line-equal _test-output-stream "g:"                      "F - test-convert-function-call-with-inout-with-compound-type/15")
3168     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-inout-with-compound-type/16")
3169     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-inout-with-compound-type/17")
3170     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-inout-with-compound-type/18")
3171     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-inout-with-compound-type/19")
3172     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-inout-with-compound-type/20")
3173     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-inout-with-compound-type/21")
3174     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-inout-with-compound-type/22")
3175     # . epilogue
3176     89/<- %esp 5/r32/ebp
3177     5d/pop-to-ebp
3178     c3/return
3180 test-convert-function-call-with-inout-with-type-parameter:
3181     # . prologue
3182     55/push-ebp
3183     89/<- %ebp 4/r32/esp
3184     # setup
3185     (clear-stream _test-input-stream)
3186     (clear-stream $_test-input-buffered-file->buffer)
3187     (clear-stream _test-output-stream)
3188     (clear-stream $_test-output-buffered-file->buffer)
3189     (clear-stream _test-error-stream)
3190     (clear-stream $_test-error-buffered-file->buffer)
3191     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
3192     68/push 0/imm32
3193     68/push 0/imm32
3194     89/<- %edx 4/r32/esp
3195     (tailor-exit-descriptor %edx 0x10)
3196     #
3197     (write _test-input-stream "fn f {\n")
3198     (write _test-input-stream "  var x: (addr int)\n")
3199     (write _test-input-stream "  g x\n")
3200     (write _test-input-stream "}\n")
3201     (write _test-input-stream "fn g a: (addr _) {\n")
3202     (write _test-input-stream "}\n")
3203     # convert
3204     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
3205     # registers except esp clobbered at this point
3206     # restore ed
3207     89/<- %edx 4/r32/esp
3208     (flush _test-output-buffered-file)
3209     (flush _test-error-buffered-file)
3210 #?     # dump _test-error-stream {{{
3211 #?     (write 2 "^")
3212 #?     (write-stream 2 _test-error-stream)
3213 #?     (write 2 "$\n")
3214 #?     (rewind-stream _test-error-stream)
3215 #?     # }}}
3216     # no error; types matched
3217     (check-stream-equal _test-error-stream  ""  "F - test-convert-function-call-with-inout-with-type-parameter: error stream should be empty")
3218     # don't bother checking the generated code; that's in the test 'test-local-clobbered-by-fn-output' below
3219     # don't restore from ebp
3220     81 0/subop/add %esp 8/imm32
3221     # . epilogue
3222     5d/pop-to-ebp
3223     c3/return
3225 test-convert-function-call-with-incorrect-inout-type:
3226     # . prologue
3227     55/push-ebp
3228     89/<- %ebp 4/r32/esp
3229     # setup
3230     (clear-stream _test-input-stream)
3231     (clear-stream $_test-input-buffered-file->buffer)
3232     (clear-stream _test-output-stream)
3233     (clear-stream $_test-output-buffered-file->buffer)
3234     (clear-stream _test-error-stream)
3235     (clear-stream $_test-error-buffered-file->buffer)
3236     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
3237     68/push 0/imm32
3238     68/push 0/imm32
3239     89/<- %edx 4/r32/esp
3240     (tailor-exit-descriptor %edx 0x10)
3241     #
3242     (write _test-input-stream "fn f {\n")
3243     (write _test-input-stream "  var x: int\n")
3244     (write _test-input-stream "  g x\n")
3245     (write _test-input-stream "}\n")
3246     (write _test-input-stream "fn g a: foo {\n")
3247     (write _test-input-stream "}\n")
3248     # convert
3249     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
3250     # registers except esp clobbered at this point
3251     # restore ed
3252     89/<- %edx 4/r32/esp
3253     (flush _test-output-buffered-file)
3254     (flush _test-error-buffered-file)
3255 #?     # dump _test-error-stream {{{
3256 #?     (write 2 "^")
3257 #?     (write-stream 2 _test-error-stream)
3258 #?     (write 2 "$\n")
3259 #?     (rewind-stream _test-error-stream)
3260 #?     # }}}
3261     # check output
3262     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-inout-type: output should be empty")
3263     (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")
3264     # check that stop(1) was called
3265     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-inout-type: exit status")
3266     # don't restore from ebp
3267     81 0/subop/add %esp 8/imm32
3268     5d/pop-to-ebp
3269     c3/return
3271 test-convert-function-call-with-inout-with-incorrect-compound-type:
3272     # . prologue
3273     55/push-ebp
3274     89/<- %ebp 4/r32/esp
3275     # setup
3276     (clear-stream _test-input-stream)
3277     (clear-stream $_test-input-buffered-file->buffer)
3278     (clear-stream _test-output-stream)
3279     (clear-stream $_test-output-buffered-file->buffer)
3280     (clear-stream _test-error-stream)
3281     (clear-stream $_test-error-buffered-file->buffer)
3282     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
3283     68/push 0/imm32
3284     68/push 0/imm32
3285     89/<- %edx 4/r32/esp
3286     (tailor-exit-descriptor %edx 0x10)
3287     #
3288     (write _test-input-stream "fn f {\n")
3289     (write _test-input-stream "  var x: (addr int)\n")
3290     (write _test-input-stream "  g x\n")
3291     (write _test-input-stream "}\n")
3292     (write _test-input-stream "fn g a: (addr bool) {\n")
3293     (write _test-input-stream "}\n")
3294     # convert
3295     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
3296     # registers except esp clobbered at this point
3297     # restore ed
3298     89/<- %edx 4/r32/esp
3299     (flush _test-output-buffered-file)
3300     (flush _test-error-buffered-file)
3301 #?     # dump _test-error-stream {{{
3302 #?     (write 2 "^")
3303 #?     (write-stream 2 _test-error-stream)
3304 #?     (write 2 "$\n")
3305 #?     (rewind-stream _test-error-stream)
3306 #?     # }}}
3307     # check output
3308     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-inout-with-incorrect-compound-type: output should be empty")
3309     (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-inout-with-incorrect-compound-type: error message")
3310     # don't restore from ebp
3311     81 0/subop/add %esp 8/imm32
3312     # . epilogue
3313     5d/pop-to-ebp
3314     c3/return
3316 test-convert-function-call-with-inout-with-multiple-type-parameters:
3317     # . prologue
3318     55/push-ebp
3319     89/<- %ebp 4/r32/esp
3320     # setup
3321     (clear-stream _test-input-stream)
3322     (clear-stream $_test-input-buffered-file->buffer)
3323     (clear-stream _test-output-stream)
3324     (clear-stream $_test-output-buffered-file->buffer)
3325     (clear-stream _test-error-stream)
3326     (clear-stream $_test-error-buffered-file->buffer)
3327     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
3328     68/push 0/imm32
3329     68/push 0/imm32
3330     89/<- %edx 4/r32/esp
3331     (tailor-exit-descriptor %edx 0x10)
3332     #
3333     (write _test-input-stream "fn f {\n")
3334     (write _test-input-stream "  var x: (addr int)\n")
3335     (write _test-input-stream "  var y: (addr int)\n")
3336     (write _test-input-stream "  g x, y\n")
3337     (write _test-input-stream "}\n")
3338     (write _test-input-stream "fn g a: (addr _), b: (addr _) {\n")
3339     (write _test-input-stream "}\n")
3340     # convert
3341     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
3342     # registers except esp clobbered at this point
3343     # restore ed
3344     89/<- %edx 4/r32/esp
3345     (flush _test-output-buffered-file)
3346     (flush _test-error-buffered-file)
3347 #?     # dump _test-error-stream {{{
3348 #?     (write 2 "^")
3349 #?     (write-stream 2 _test-error-stream)
3350 #?     (write 2 "$\n")
3351 #?     (rewind-stream _test-error-stream)
3352 #?     # }}}
3353     # no errors
3354     (check-stream-equal _test-error-stream  ""  "F - test-convert-function-call-with-inout-with-multiple-type-parameters: error stream should be empty")
3355     # don't bother checking the generated code
3356     # don't restore from ebp
3357     81 0/subop/add %esp 8/imm32
3358     # . epilogue
3359     5d/pop-to-ebp
3360     c3/return
3362 test-type-parameter-matches-rest-of-type:
3363     # . prologue
3364     55/push-ebp
3365     89/<- %ebp 4/r32/esp
3366     # setup
3367     (clear-stream _test-input-stream)
3368     (clear-stream $_test-input-buffered-file->buffer)
3369     (clear-stream _test-output-stream)
3370     (clear-stream $_test-output-buffered-file->buffer)
3371     (clear-stream _test-error-stream)
3372     (clear-stream $_test-error-buffered-file->buffer)
3373     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
3374     68/push 0/imm32
3375     68/push 0/imm32
3376     89/<- %edx 4/r32/esp
3377     (tailor-exit-descriptor %edx 0x10)
3378     #
3379     (write _test-input-stream "fn f {\n")
3380     (write _test-input-stream "  var x: (addr array int)\n")
3381     (write _test-input-stream "  g x\n")
3382     (write _test-input-stream "}\n")
3383     (write _test-input-stream "fn g a: (addr _) {\n")
3384     (write _test-input-stream "}\n")
3385     # convert
3386     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
3387     # registers except esp clobbered at this point
3388     # restore ed
3389     89/<- %edx 4/r32/esp
3390     (flush _test-output-buffered-file)
3391     (flush _test-error-buffered-file)
3392 #?     # dump _test-error-stream {{{
3393 #?     (write 2 "^")
3394 #?     (write-stream 2 _test-error-stream)
3395 #?     (write 2 "$\n")
3396 #?     (rewind-stream _test-error-stream)
3397 #?     # }}}
3398     # no errors
3399     (check-stream-equal _test-error-stream  ""  "F - test-type-parameter-matches-rest-of-type: error stream should be empty")
3400     # don't bother checking the generated code
3401     # don't restore from ebp
3402     81 0/subop/add %esp 8/imm32
3403     # . epilogue
3404     5d/pop-to-ebp
3405     c3/return
3407 test-convert-function-call-with-inout-with-incompatible-type-parameters:
3408     # . prologue
3409     55/push-ebp
3410     89/<- %ebp 4/r32/esp
3411     # setup
3412     (clear-stream _test-input-stream)
3413     (clear-stream $_test-input-buffered-file->buffer)
3414     (clear-stream _test-output-stream)
3415     (clear-stream $_test-output-buffered-file->buffer)
3416     (clear-stream _test-error-stream)
3417     (clear-stream $_test-error-buffered-file->buffer)
3418     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
3419     68/push 0/imm32
3420     68/push 0/imm32
3421     89/<- %edx 4/r32/esp
3422     (tailor-exit-descriptor %edx 0x10)
3423     #
3424     (write _test-input-stream "fn f {\n")
3425     (write _test-input-stream "  var x: (addr int)\n")
3426     (write _test-input-stream "  var y: (addr boolean)\n")
3427     (write _test-input-stream "  g x, y\n")
3428     (write _test-input-stream "}\n")
3429     (write _test-input-stream "fn g a: (addr _T), b: (addr _T) {\n")
3430     (write _test-input-stream "}\n")
3431     # convert
3432     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
3433     # registers except esp clobbered at this point
3434     # restore ed
3435     89/<- %edx 4/r32/esp
3436     (flush _test-output-buffered-file)
3437     (flush _test-error-buffered-file)
3438 #?     # dump _test-error-stream {{{
3439 #?     (write 2 "^")
3440 #?     (write-stream 2 _test-error-stream)
3441 #?     (write 2 "$\n")
3442 #?     (rewind-stream _test-error-stream)
3443 #?     # }}}
3444     # check output
3445     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-inout-with-incompatible-type-parameters: output should be empty")
3446     (check-next-stream-line-equal _test-error-stream  "fn f: call g: type for inout 'y' is not right"  "F - test-convert-function-call-with-inout-with-incompatible-type-parameters: error message")
3447     # don't restore from ebp
3448     81 0/subop/add %esp 8/imm32
3449     # . epilogue
3450     5d/pop-to-ebp
3451     c3/return
3453 test-convert-function-call-with-too-few-inouts:
3454     # . prologue
3455     55/push-ebp
3456     89/<- %ebp 4/r32/esp
3457     # setup
3458     (clear-stream _test-input-stream)
3459     (clear-stream $_test-input-buffered-file->buffer)
3460     (clear-stream _test-output-stream)
3461     (clear-stream $_test-output-buffered-file->buffer)
3462     (clear-stream _test-error-stream)
3463     (clear-stream $_test-error-buffered-file->buffer)
3464     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
3465     68/push 0/imm32
3466     68/push 0/imm32
3467     89/<- %edx 4/r32/esp
3468     (tailor-exit-descriptor %edx 0x10)
3469     #
3470     (write _test-input-stream "fn f {\n")
3471     (write _test-input-stream "  g\n")
3472     (write _test-input-stream "}\n")
3473     (write _test-input-stream "fn g a: int {\n")
3474     (write _test-input-stream "}\n")
3475     # convert
3476     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
3477     # registers except esp clobbered at this point
3478     # restore ed
3479     89/<- %edx 4/r32/esp
3480     (flush _test-output-buffered-file)
3481     (flush _test-error-buffered-file)
3482 #?     # dump _test-error-stream {{{
3483 #?     (write 2 "^")
3484 #?     (write-stream 2 _test-error-stream)
3485 #?     (write 2 "$\n")
3486 #?     (rewind-stream _test-error-stream)
3487 #?     # }}}
3488     # check output
3489     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-few-inouts: output should be empty")
3490     (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")
3491     # check that stop(1) was called
3492     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-few-inouts: exit status")
3493     # don't restore from ebp
3494     81 0/subop/add %esp 8/imm32
3495     5d/pop-to-ebp
3496     c3/return
3498 test-convert-function-call-with-too-many-inouts:
3499     # . prologue
3500     55/push-ebp
3501     89/<- %ebp 4/r32/esp
3502     # setup
3503     (clear-stream _test-input-stream)
3504     (clear-stream $_test-input-buffered-file->buffer)
3505     (clear-stream _test-output-stream)
3506     (clear-stream $_test-output-buffered-file->buffer)
3507     (clear-stream _test-error-stream)
3508     (clear-stream $_test-error-buffered-file->buffer)
3509     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
3510     68/push 0/imm32
3511     68/push 0/imm32
3512     89/<- %edx 4/r32/esp
3513     (tailor-exit-descriptor %edx 0x10)
3514     #
3515     (write _test-input-stream "fn f {\n")
3516     (write _test-input-stream "  var x: int\n")
3517     (write _test-input-stream "  g x\n")
3518     (write _test-input-stream "}\n")
3519     (write _test-input-stream "fn g {\n")
3520     (write _test-input-stream "}\n")
3521     # convert
3522     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
3523     # registers except esp clobbered at this point
3524     # restore ed
3525     89/<- %edx 4/r32/esp
3526     (flush _test-output-buffered-file)
3527     (flush _test-error-buffered-file)
3528 #?     # dump _test-error-stream {{{
3529 #?     (write 2 "^")
3530 #?     (write-stream 2 _test-error-stream)
3531 #?     (write 2 "$\n")
3532 #?     (rewind-stream _test-error-stream)
3533 #?     # }}}
3534     # check output
3535     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-many-inouts: output should be empty")
3536     (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")
3537     # check that stop(1) was called
3538     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-many-inouts: exit status")
3539     # don't restore from ebp
3540     81 0/subop/add %esp 8/imm32
3541     5d/pop-to-ebp
3542     c3/return
3544 test-convert-function-call-with-incorrect-output-type:
3545     # . prologue
3546     55/push-ebp
3547     89/<- %ebp 4/r32/esp
3548     # setup
3549     (clear-stream _test-input-stream)
3550     (clear-stream $_test-input-buffered-file->buffer)
3551     (clear-stream _test-output-stream)
3552     (clear-stream $_test-output-buffered-file->buffer)
3553     (clear-stream _test-error-stream)
3554     (clear-stream $_test-error-buffered-file->buffer)
3555     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
3556     68/push 0/imm32
3557     68/push 0/imm32
3558     89/<- %edx 4/r32/esp
3559     (tailor-exit-descriptor %edx 0x10)
3560     #
3561     (write _test-input-stream "fn f {\n")
3562     (write _test-input-stream "  var x/eax: int <- g\n")
3563     (write _test-input-stream "}\n")
3564     (write _test-input-stream "fn g -> _/eax: foo {\n")
3565     (write _test-input-stream "}\n")
3566     # convert
3567     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
3568     # registers except esp clobbered at this point
3569     # restore ed
3570     89/<- %edx 4/r32/esp
3571     (flush _test-output-buffered-file)
3572     (flush _test-error-buffered-file)
3573 #?     # dump _test-error-stream {{{
3574 #?     (write 2 "^")
3575 #?     (write-stream 2 _test-error-stream)
3576 #?     (write 2 "$\n")
3577 #?     (rewind-stream _test-error-stream)
3578 #?     # }}}
3579     # check output
3580     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-output-type: output should be empty")
3581     (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")
3582     # check that stop(1) was called
3583     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-output-type: exit status")
3584     # don't restore from ebp
3585     81 0/subop/add %esp 8/imm32
3586     5d/pop-to-ebp
3587     c3/return
3589 test-convert-function-call-with-too-few-outputs:
3590     # . prologue
3591     55/push-ebp
3592     89/<- %ebp 4/r32/esp
3593     # setup
3594     (clear-stream _test-input-stream)
3595     (clear-stream $_test-input-buffered-file->buffer)
3596     (clear-stream _test-output-stream)
3597     (clear-stream $_test-output-buffered-file->buffer)
3598     (clear-stream _test-error-stream)
3599     (clear-stream $_test-error-buffered-file->buffer)
3600     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
3601     68/push 0/imm32
3602     68/push 0/imm32
3603     89/<- %edx 4/r32/esp
3604     (tailor-exit-descriptor %edx 0x10)
3605     #
3606     (write _test-input-stream "fn f {\n")
3607     (write _test-input-stream "  g\n")
3608     (write _test-input-stream "}\n")
3609     (write _test-input-stream "fn g -> _/eax: int {\n")
3610     (write _test-input-stream "}\n")
3611     # convert
3612     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
3613     # registers except esp clobbered at this point
3614     # restore ed
3615     89/<- %edx 4/r32/esp
3616     (flush _test-output-buffered-file)
3617     (flush _test-error-buffered-file)
3618 #?     # dump _test-error-stream {{{
3619 #?     (write 2 "^")
3620 #?     (write-stream 2 _test-error-stream)
3621 #?     (write 2 "$\n")
3622 #?     (rewind-stream _test-error-stream)
3623 #?     # }}}
3624     # check output
3625     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-few-outputs: output should be empty")
3626     (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")
3627     # check that stop(1) was called
3628     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-few-outputs: exit status")
3629     # don't restore from ebp
3630     81 0/subop/add %esp 8/imm32
3631     5d/pop-to-ebp
3632     c3/return
3634 test-convert-function-call-with-too-many-outputs:
3635     # . prologue
3636     55/push-ebp
3637     89/<- %ebp 4/r32/esp
3638     # setup
3639     (clear-stream _test-input-stream)
3640     (clear-stream $_test-input-buffered-file->buffer)
3641     (clear-stream _test-output-stream)
3642     (clear-stream $_test-output-buffered-file->buffer)
3643     (clear-stream _test-error-stream)
3644     (clear-stream $_test-error-buffered-file->buffer)
3645     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
3646     68/push 0/imm32
3647     68/push 0/imm32
3648     89/<- %edx 4/r32/esp
3649     (tailor-exit-descriptor %edx 0x10)
3650     #
3651     (write _test-input-stream "fn f {\n")
3652     (write _test-input-stream "  var x/eax: int <- g\n")
3653     (write _test-input-stream "}\n")
3654     (write _test-input-stream "fn g {\n")
3655     (write _test-input-stream "}\n")
3656     # convert
3657     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
3658     # registers except esp clobbered at this point
3659     # restore ed
3660     89/<- %edx 4/r32/esp
3661     (flush _test-output-buffered-file)
3662     (flush _test-error-buffered-file)
3663 #?     # dump _test-error-stream {{{
3664 #?     (write 2 "^")
3665 #?     (write-stream 2 _test-error-stream)
3666 #?     (write 2 "$\n")
3667 #?     (rewind-stream _test-error-stream)
3668 #?     # }}}
3669     # check output
3670     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-many-outputs: output should be empty")
3671     (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")
3672     # check that stop(1) was called
3673     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-many-outputs: exit status")
3674     # don't restore from ebp
3675     81 0/subop/add %esp 8/imm32
3676     5d/pop-to-ebp
3677     c3/return
3679 test-convert-function-call-with-missing-output-register:
3680     # . prologue
3681     55/push-ebp
3682     89/<- %ebp 4/r32/esp
3683     # setup
3684     (clear-stream _test-input-stream)
3685     (clear-stream $_test-input-buffered-file->buffer)
3686     (clear-stream _test-output-stream)
3687     (clear-stream $_test-output-buffered-file->buffer)
3688     (clear-stream _test-error-stream)
3689     (clear-stream $_test-error-buffered-file->buffer)
3690     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
3691     68/push 0/imm32
3692     68/push 0/imm32
3693     89/<- %edx 4/r32/esp
3694     (tailor-exit-descriptor %edx 0x10)
3695     #
3696     (write _test-input-stream "fn f {\n")
3697     (write _test-input-stream "  var x: int\n")
3698     (write _test-input-stream "  x <- g\n")
3699     (write _test-input-stream "}\n")
3700     (write _test-input-stream "fn g -> _/eax: int {\n")
3701     (write _test-input-stream "}\n")
3702     # convert
3703     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
3704     # registers except esp clobbered at this point
3705     # restore ed
3706     89/<- %edx 4/r32/esp
3707     (flush _test-output-buffered-file)
3708     (flush _test-error-buffered-file)
3709 #?     # dump _test-error-stream {{{
3710 #?     (write 2 "^")
3711 #?     (write-stream 2 _test-error-stream)
3712 #?     (write 2 "$\n")
3713 #?     (rewind-stream _test-error-stream)
3714 #?     # }}}
3715     # check output
3716     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-missing-output-register: output should be empty")
3717     (check-next-stream-line-equal _test-error-stream  "fn f: call g: output 'x' is not in a register"  "F - test-convert-function-call-with-missing-output-register: error message")
3718     # check that stop(1) was called
3719     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-missing-output-register: exit status")
3720     # don't restore from ebp
3721     81 0/subop/add %esp 8/imm32
3722     5d/pop-to-ebp
3723     c3/return
3725 test-convert-function-call-with-incorrect-output-register:
3726     # . prologue
3727     55/push-ebp
3728     89/<- %ebp 4/r32/esp
3729     # setup
3730     (clear-stream _test-input-stream)
3731     (clear-stream $_test-input-buffered-file->buffer)
3732     (clear-stream _test-output-stream)
3733     (clear-stream $_test-output-buffered-file->buffer)
3734     (clear-stream _test-error-stream)
3735     (clear-stream $_test-error-buffered-file->buffer)
3736     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
3737     68/push 0/imm32
3738     68/push 0/imm32
3739     89/<- %edx 4/r32/esp
3740     (tailor-exit-descriptor %edx 0x10)
3741     #
3742     (write _test-input-stream "fn f {\n")
3743     (write _test-input-stream "  var x/ecx: int <- g\n")
3744     (write _test-input-stream "}\n")
3745     (write _test-input-stream "fn g -> _/eax: int {\n")
3746     (write _test-input-stream "}\n")
3747     # convert
3748     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
3749     # registers except esp clobbered at this point
3750     # restore ed
3751     89/<- %edx 4/r32/esp
3752     (flush _test-output-buffered-file)
3753     (flush _test-error-buffered-file)
3754 #?     # dump _test-error-stream {{{
3755 #?     (write 2 "^")
3756 #?     (write-stream 2 _test-error-stream)
3757 #?     (write 2 "$\n")
3758 #?     (rewind-stream _test-error-stream)
3759 #?     # }}}
3760     # check output
3761     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-output-register: output should be empty")
3762     (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")
3763     # check that stop(1) was called
3764     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-output-register: exit status")
3765     # don't restore from ebp
3766     81 0/subop/add %esp 8/imm32
3767     5d/pop-to-ebp
3768     c3/return
3770 test-convert-function-with-local-var-dereferenced:
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 x/ecx: (addr int) <- copy 0\n")
3782     (write _test-input-stream "  increment *x\n")
3783     (write _test-input-stream "}\n")
3784     # convert
3785     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
3786     (flush _test-output-buffered-file)
3787 #?     # dump _test-output-stream {{{
3788 #?     (write 2 "^")
3789 #?     (write-stream 2 _test-output-stream)
3790 #?     (write 2 "$\n")
3791 #?     (rewind-stream _test-output-stream)
3792 #?     # }}}
3793     # check output
3794     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-dereferenced/0")
3795     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-dereferenced/1")
3796     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-dereferenced/2")
3797     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-dereferenced/3")
3798     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-dereferenced/4")
3799     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-dereferenced/5")
3800     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-dereferenced/6")
3801     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-local-var-dereferenced/7")
3802     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *ecx"  "F - test-convert-function-with-local-var-dereferenced/8")
3803     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-dereferenced/9")
3804     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-dereferenced/10")
3805     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-dereferenced/11")
3806     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-dereferenced/12")
3807     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-dereferenced/13")
3808     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-dereferenced/14")
3809     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-dereferenced/15")
3810     # . epilogue
3811     89/<- %esp 5/r32/ebp
3812     5d/pop-to-ebp
3813     c3/return
3815 test-dereference-of-var-on-stack:
3816     # . prologue
3817     55/push-ebp
3818     89/<- %ebp 4/r32/esp
3819     # setup
3820     (clear-stream _test-input-stream)
3821     (clear-stream $_test-input-buffered-file->buffer)
3822     (clear-stream _test-output-stream)
3823     (clear-stream $_test-output-buffered-file->buffer)
3824     (clear-stream _test-error-stream)
3825     (clear-stream $_test-error-buffered-file->buffer)
3826     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
3827     68/push 0/imm32
3828     68/push 0/imm32
3829     89/<- %edx 4/r32/esp
3830     (tailor-exit-descriptor %edx 0x10)
3831     #
3832     (write _test-input-stream "fn foo {\n")
3833     (write _test-input-stream "  var x: (addr int)\n")
3834     (write _test-input-stream "  increment *x\n")
3835     (write _test-input-stream "}\n")
3836     # convert
3837     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
3838     # registers except esp clobbered at this point
3839     # restore ed
3840     89/<- %edx 4/r32/esp
3841     (flush _test-output-buffered-file)
3842     (flush _test-error-buffered-file)
3843 #?     # dump _test-error-stream {{{
3844 #?     (write 2 "^")
3845 #?     (write-stream 2 _test-error-stream)
3846 #?     (write 2 "$\n")
3847 #?     (rewind-stream _test-error-stream)
3848 #?     # }}}
3849     # check output
3850     (check-stream-equal _test-output-stream  ""  "F - test-dereference-of-var-on-stack: output should be empty")
3851     (check-next-stream-line-equal _test-error-stream  "fn foo: cannot dereference var 'x' on stack"  "F - test-dereference-of-var-on-stack: error message")
3852     # check that stop(1) was called
3853     (check-ints-equal *(edx+4) 2 "F - test-dereference-of-var-on-stack: exit status")
3854     # don't restore from ebp
3855     81 0/subop/add %esp 8/imm32
3856     # . epilogue
3857     5d/pop-to-ebp
3858     c3/return
3860 test-convert-function-with-byte-operations:
3861     # . prologue
3862     55/push-ebp
3863     89/<- %ebp 4/r32/esp
3864     # setup
3865     (clear-stream _test-input-stream)
3866     (clear-stream $_test-input-buffered-file->buffer)
3867     (clear-stream _test-output-stream)
3868     (clear-stream $_test-output-buffered-file->buffer)
3869     #
3870     (write _test-input-stream "fn foo {\n")
3871     (write _test-input-stream "  var x/eax: byte <- copy 0\n")
3872     (write _test-input-stream "  var y/ecx: byte <- copy 0\n")
3873     (write _test-input-stream "  y <- copy-byte x\n")
3874     (write _test-input-stream "  var z/edx: (addr byte) <- copy 0\n")
3875     (write _test-input-stream "  y <- copy-byte *z\n")
3876     (write _test-input-stream "  copy-byte-to *z, x\n")
3877     (write _test-input-stream "}\n")
3878     # convert
3879     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
3880     (flush _test-output-buffered-file)
3881 #?     # dump _test-output-stream {{{
3882 #?     (write 2 "^")
3883 #?     (write-stream 2 _test-output-stream)
3884 #?     (write 2 "$\n")
3885 #?     (rewind-stream _test-output-stream)
3886 #?     # }}}
3887     # check output
3888     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-function-with-byte-operations/0")
3889     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-function-with-byte-operations/1")
3890     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-function-with-byte-operations/2")
3891     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-function-with-byte-operations/3")
3892     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-function-with-byte-operations/4")
3893     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-function-with-byte-operations/5")
3894     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-function-with-byte-operations/6")
3895     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-function-with-byte-operations/7")
3896     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-function-with-byte-operations/8")
3897     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"                  "F - test-convert-function-with-byte-operations/9")
3898     (check-next-stream-line-equal _test-output-stream "    8a/byte-> %eax 0x00000001/r32"           "F - test-convert-function-with-byte-operations/10")
3899     (check-next-stream-line-equal _test-output-stream "    81 4/subop/and %ecx 0xff/imm32"          "F - test-convert-function-with-byte-operations/11")
3900     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %edx"                    "F - test-convert-function-with-byte-operations/12")
3901     (check-next-stream-line-equal _test-output-stream "    ba/copy-to-edx 0/imm32"                  "F - test-convert-function-with-byte-operations/13")
3902     (check-next-stream-line-equal _test-output-stream "    8a/byte-> *edx 0x00000001/r32"           "F - test-convert-function-with-byte-operations/14")
3903     (check-next-stream-line-equal _test-output-stream "    81 4/subop/and %ecx 0xff/imm32"          "F - test-convert-function-with-byte-operations/15")
3904     (check-next-stream-line-equal _test-output-stream "    88/byte<- *edx 0x00000000/r32"           "F - test-convert-function-with-byte-operations/16")
3905     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %edx"                     "F - test-convert-function-with-byte-operations/17")
3906     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-function-with-byte-operations/18")
3907     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-function-with-byte-operations/19")
3908     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-function-with-byte-operations/20")
3909     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-function-with-byte-operations/21")
3910     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-function-with-byte-operations/22")
3911     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-function-with-byte-operations/23")
3912     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-function-with-byte-operations/24")
3913     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-function-with-byte-operations/25")
3914     # . epilogue
3915     89/<- %esp 5/r32/ebp
3916     5d/pop-to-ebp
3917     c3/return
3919 # variables of type 'byte' are not allowed on the stack
3920 test-byte-values-on-stack:
3921     # . prologue
3922     55/push-ebp
3923     89/<- %ebp 4/r32/esp
3924     # setup
3925     (clear-stream _test-input-stream)
3926     (clear-stream $_test-input-buffered-file->buffer)
3927     (clear-stream _test-output-stream)
3928     (clear-stream $_test-output-buffered-file->buffer)
3929     (clear-stream _test-error-stream)
3930     (clear-stream $_test-error-buffered-file->buffer)
3931     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
3932     68/push 0/imm32
3933     68/push 0/imm32
3934     89/<- %edx 4/r32/esp
3935     (tailor-exit-descriptor %edx 0x10)
3936     #
3937     (write _test-input-stream "fn foo {\n")
3938     (write _test-input-stream "  var x: byte\n")
3939     (write _test-input-stream "}\n")
3940     # convert
3941     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
3942     # registers except esp clobbered at this point
3943     # restore ed
3944     89/<- %edx 4/r32/esp
3945     (flush _test-output-buffered-file)
3946     (flush _test-error-buffered-file)
3947 #?     # dump _test-error-stream {{{
3948 #?     (write 2 "^")
3949 #?     (write-stream 2 _test-error-stream)
3950 #?     (write 2 "$\n")
3951 #?     (rewind-stream _test-error-stream)
3952 #?     # }}}
3953     # check output
3954     (check-stream-equal _test-output-stream  ""  "F - test-byte-values-on-stack: output should be empty")
3955     (check-next-stream-line-equal _test-error-stream  "fn foo: var 'x' of type 'byte' cannot be on the stack"  "F - test-byte-values-on-stack: error message")
3956     # check that stop(1) was called
3957     (check-ints-equal *(edx+4) 2 "F - test-byte-values-on-stack: exit status")
3958     # don't restore from ebp
3959     81 0/subop/add %esp 8/imm32
3960     # . epilogue
3961     5d/pop-to-ebp
3962     c3/return
3964 # variables of type 'byte' are not allowed in esi or edi
3965 test-byte-values-in-unsupported-registers:
3966     # . prologue
3967     55/push-ebp
3968     89/<- %ebp 4/r32/esp
3969     # setup
3970     (clear-stream _test-input-stream)
3971     (clear-stream $_test-input-buffered-file->buffer)
3972     (clear-stream _test-output-stream)
3973     (clear-stream $_test-output-buffered-file->buffer)
3974     (clear-stream _test-error-stream)
3975     (clear-stream $_test-error-buffered-file->buffer)
3976     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
3977     68/push 0/imm32
3978     68/push 0/imm32
3979     89/<- %edx 4/r32/esp
3980     (tailor-exit-descriptor %edx 0x10)
3981     #
3982     (write _test-input-stream "fn foo {\n")
3983     (write _test-input-stream "  var x/esi: byte <- copy 0\n")
3984     (write _test-input-stream "}\n")
3985     # convert
3986     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
3987     # registers except esp clobbered at this point
3988     # restore ed
3989     89/<- %edx 4/r32/esp
3990     (flush _test-output-buffered-file)
3991     (flush _test-error-buffered-file)
3992 #?     # dump _test-error-stream {{{
3993 #?     (write 2 "^")
3994 #?     (write-stream 2 _test-error-stream)
3995 #?     (write 2 "$\n")
3996 #?     (rewind-stream _test-error-stream)
3997 #?     # }}}
3998     # check output
3999     (check-stream-equal _test-output-stream  ""  "F - test-byte-values-in-unsupported-registers: output should be empty")
4000     (check-next-stream-line-equal _test-error-stream  "fn foo: var 'x' of type 'byte' cannot be in esi or edi"  "F - test-byte-values-in-unsupported-registers: error message")
4001     # check that stop(1) was called
4002     (check-ints-equal *(edx+4) 2 "F - test-byte-values-in-unsupported-registers: exit status")
4003     # don't restore from ebp
4004     81 0/subop/add %esp 8/imm32
4005     # . epilogue
4006     5d/pop-to-ebp
4007     c3/return
4009 # variables of type 'byte' _can_ be function args. They then occupy 4 bytes.
4010 test-copy-byte-var-from-fn-arg:
4011     # . prologue
4012     55/push-ebp
4013     89/<- %ebp 4/r32/esp
4014     # setup
4015     (clear-stream _test-input-stream)
4016     (clear-stream $_test-input-buffered-file->buffer)
4017     (clear-stream _test-output-stream)
4018     (clear-stream $_test-output-buffered-file->buffer)
4019     #
4020     (write _test-input-stream "fn foo x: byte, y: int {\n")
4021     (write _test-input-stream "  var a/eax: byte <- copy x\n")
4022     (write _test-input-stream "  var b/eax: int <- copy y\n")
4023     (write _test-input-stream "}\n")
4024     # convert
4025     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
4026     (flush _test-output-buffered-file)
4027 #?     # dump _test-output-stream {{{
4028 #?     (write 2 "^")
4029 #?     (write-stream 2 _test-output-stream)
4030 #?     (write 2 "$\n")
4031 #?     (rewind-stream _test-output-stream)
4032 #?     # }}}
4033     # check output
4034     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-copy-byte-from-fn-arg/0")
4035     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-copy-byte-from-fn-arg/1")
4036     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-copy-byte-from-fn-arg/2")
4037     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-copy-byte-from-fn-arg/3")
4038     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-copy-byte-from-fn-arg/4")
4039     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-copy-byte-from-fn-arg/5")
4040     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-copy-byte-from-fn-arg/6")
4041     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-copy-byte-from-fn-arg/7")
4042     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x0000000c) 0x00000000/r32"  "F - test-copy-byte-from-fn-arg/8")
4043     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"   "F - test-copy-byte-from-fn-arg/9")
4044     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-copy-byte-from-fn-arg/10")
4045     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-copy-byte-from-fn-arg/11")
4046     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-copy-byte-from-fn-arg/12")
4047     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-copy-byte-from-fn-arg/13")
4048     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-copy-byte-from-fn-arg/14")
4049     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-copy-byte-from-fn-arg/15")
4050     # . epilogue
4051     89/<- %esp 5/r32/ebp
4052     5d/pop-to-ebp
4053     c3/return
4055 test-convert-compare-register-with-literal:
4056     # . prologue
4057     55/push-ebp
4058     89/<- %ebp 4/r32/esp
4059     # setup
4060     (clear-stream _test-input-stream)
4061     (clear-stream $_test-input-buffered-file->buffer)
4062     (clear-stream _test-output-stream)
4063     (clear-stream $_test-output-buffered-file->buffer)
4064     #
4065     (write _test-input-stream "fn foo {\n")
4066     (write _test-input-stream "  var x/ecx: int <- copy 0\n")
4067     (write _test-input-stream "  compare x, 0\n")
4068     (write _test-input-stream "}\n")
4069     # convert
4070     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
4071     (flush _test-output-buffered-file)
4072 #?     # dump _test-output-stream {{{
4073 #?     (write 2 "^")
4074 #?     (write-stream 2 _test-output-stream)
4075 #?     (write 2 "$\n")
4076 #?     (rewind-stream _test-output-stream)
4077 #?     # }}}
4078     # check output
4079     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-compare-register-with-literal/0")
4080     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-compare-register-with-literal/1")
4081     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-compare-register-with-literal/2")
4082     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-compare-register-with-literal/3")
4083     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-compare-register-with-literal/4")
4084     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-compare-register-with-literal/5")
4085     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
4086     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-compare-register-with-literal/7")
4087     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %ecx 0/imm32"  "F - test-convert-compare-register-with-literal/8")
4088     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
4089     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-compare-register-with-literal/10")
4090     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-compare-register-with-literal/11")
4091     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-compare-register-with-literal/12")
4092     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-compare-register-with-literal/13")
4093     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-compare-register-with-literal/14")
4094     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-compare-register-with-literal/15")
4095     # . epilogue
4096     89/<- %esp 5/r32/ebp
4097     5d/pop-to-ebp
4098     c3/return
4100 test-convert-compare-byte-with-literal:
4101     # . prologue
4102     55/push-ebp
4103     89/<- %ebp 4/r32/esp
4104     # setup
4105     (clear-stream _test-input-stream)
4106     (clear-stream $_test-input-buffered-file->buffer)
4107     (clear-stream _test-output-stream)
4108     (clear-stream $_test-output-buffered-file->buffer)
4109     #
4110     (write _test-input-stream "fn foo {\n")
4111     (write _test-input-stream "  var x/ecx: byte <- copy 0\n")
4112     (write _test-input-stream "  compare x, 0\n")
4113     (write _test-input-stream "}\n")
4114     # convert
4115     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
4116     (flush _test-output-buffered-file)
4117 #?     # dump _test-output-stream {{{
4118 #?     (write 2 "^")
4119 #?     (write-stream 2 _test-output-stream)
4120 #?     (write 2 "$\n")
4121 #?     (rewind-stream _test-output-stream)
4122 #?     # }}}
4123     # no errors; output is identical to test-convert-compare-register-with-literal
4124     # . epilogue
4125     89/<- %esp 5/r32/ebp
4126     5d/pop-to-ebp
4127     c3/return
4129 test-unknown-variable:
4130     # . prologue
4131     55/push-ebp
4132     89/<- %ebp 4/r32/esp
4133     # setup
4134     (clear-stream _test-input-stream)
4135     (clear-stream $_test-input-buffered-file->buffer)
4136     (clear-stream _test-output-stream)
4137     (clear-stream $_test-output-buffered-file->buffer)
4138     (clear-stream _test-error-stream)
4139     (clear-stream $_test-error-buffered-file->buffer)
4140     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
4141     68/push 0/imm32
4142     68/push 0/imm32
4143     89/<- %edx 4/r32/esp
4144     (tailor-exit-descriptor %edx 0x10)
4145     #
4146     (write _test-input-stream "fn foo {\n")
4147     (write _test-input-stream "  compare x, 0\n")
4148     (write _test-input-stream "}\n")
4149     # convert
4150     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
4151     # registers except esp clobbered at this point
4152     # restore ed
4153     89/<- %edx 4/r32/esp
4154     (flush _test-output-buffered-file)
4155     (flush _test-error-buffered-file)
4156 #?     # dump _test-error-stream {{{
4157 #?     (write 2 "^")
4158 #?     (write-stream 2 _test-error-stream)
4159 #?     (write 2 "$\n")
4160 #?     (rewind-stream _test-error-stream)
4161 #?     # }}}
4162     # check output
4163     (check-stream-equal _test-output-stream  ""  "F - test-unknown-variable: output should be empty")
4164     (check-next-stream-line-equal _test-error-stream  "fn foo: unknown variable 'x'"  "F - test-unknown-variable: error message")
4165     # check that stop(1) was called
4166     (check-ints-equal *(edx+4) 2 "F - test-unknown-variable: exit status")
4167     # don't restore from ebp
4168     81 0/subop/add %esp 8/imm32
4169     # . epilogue
4170     5d/pop-to-ebp
4171     c3/return
4173 test-convert-function-with-local-var-in-block:
4174     # . prologue
4175     55/push-ebp
4176     89/<- %ebp 4/r32/esp
4177     # setup
4178     (clear-stream _test-input-stream)
4179     (clear-stream $_test-input-buffered-file->buffer)
4180     (clear-stream _test-output-stream)
4181     (clear-stream $_test-output-buffered-file->buffer)
4182     #
4183     (write _test-input-stream "fn foo {\n")
4184     (write _test-input-stream "  {\n")
4185     (write _test-input-stream "    var x: int\n")
4186     (write _test-input-stream "    increment x\n")
4187     (write _test-input-stream "  }\n")
4188     (write _test-input-stream "}\n")
4189     # convert
4190     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
4191     (flush _test-output-buffered-file)
4192 #?     # dump _test-output-stream {{{
4193 #?     (write 2 "^")
4194 #?     (write-stream 2 _test-output-stream)
4195 #?     (write 2 "$\n")
4196 #?     (rewind-stream _test-output-stream)
4197 #?     # }}}
4198     # check output
4199     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-block/0")
4200     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-block/1")
4201     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-block/2")
4202     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-block/3")
4203     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-block/4")
4204     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-block/5")
4205     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-block/6")
4206     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-local-var-in-block/7")
4207     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-block/8")
4208     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-block/9")
4209     (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")
4210     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-block/11")
4211     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-local-var-in-block/12")
4212     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-block/13")
4213     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-block/14")
4214     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-block/15")
4215     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-block/16")
4216     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-block/17")
4217     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-block/18")
4218     # . epilogue
4219     89/<- %esp 5/r32/ebp
4220     5d/pop-to-ebp
4221     c3/return
4223 test-convert-function-with-local-var-in-mem-after-block:
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 "  {\n")
4235     (write _test-input-stream "    var y: int\n")
4236     (write _test-input-stream "  }\n")
4237     (write _test-input-stream "  var x: int\n")
4238     (write _test-input-stream "  increment x\n")
4239     (write _test-input-stream "}\n")
4240     # convert
4241     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
4242     (flush _test-output-buffered-file)
4243 #?     # dump _test-output-stream {{{
4244 #?     (write 2 "^")
4245 #?     (write-stream 2 _test-output-stream)
4246 #?     (write 2 "$\n")
4247 #?     (rewind-stream _test-output-stream)
4248 #?     # }}}
4249     # check output
4250     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-mem-after-block/0")
4251     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-mem-after-block/1")
4252     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-mem-after-block/2")
4253     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-mem-after-block/3")
4254     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-mem-after-block/4")
4255     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-mem-after-block/5")
4256     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-mem-after-block/6")
4257     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-local-var-in-mem-after-block/7")
4258     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-mem-after-block/8")
4259     (check-next-stream-line-equal _test-output-stream "      81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-local-var-in-mem-after-block/9")
4260     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-mem-after-block/10")
4261     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-local-var-in-mem-after-block/11")
4262     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-in-mem-after-block/12")
4263     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-mem-after-block/13")
4264     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-local-var-in-mem-after-block/14")
4265     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-mem-after-block/15")
4266     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-mem-after-block/16")
4267     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-mem-after-block/17")
4268     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-mem-after-block/18")
4269     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-mem-after-block/19")
4270     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-mem-after-block/20")
4271     # . epilogue
4272     89/<- %esp 5/r32/ebp
4273     5d/pop-to-ebp
4274     c3/return
4276 test-convert-function-with-local-var-in-named-block:
4277     # . prologue
4278     55/push-ebp
4279     89/<- %ebp 4/r32/esp
4280     # setup
4281     (clear-stream _test-input-stream)
4282     (clear-stream $_test-input-buffered-file->buffer)
4283     (clear-stream _test-output-stream)
4284     (clear-stream $_test-output-buffered-file->buffer)
4285     #
4286     (write _test-input-stream "fn foo {\n")
4287     (write _test-input-stream "  $bar: {\n")
4288     (write _test-input-stream "    var x: int\n")
4289     (write _test-input-stream "    increment x\n")
4290     (write _test-input-stream "  }\n")
4291     (write _test-input-stream "}\n")
4292     # convert
4293     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
4294     (flush _test-output-buffered-file)
4295 #?     # dump _test-output-stream {{{
4296 #?     (write 2 "^")
4297 #?     (write-stream 2 _test-output-stream)
4298 #?     (write 2 "$\n")
4299 #?     (rewind-stream _test-output-stream)
4300 #?     # }}}
4301     # check output
4302     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-named-block/0")
4303     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-named-block/1")
4304     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-named-block/2")
4305     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-named-block/3")
4306     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-named-block/4")
4307     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-named-block/5")
4308     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-named-block/6")
4309     (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-local-var-in-named-block/7")
4310     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-named-block/8")
4311     (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")
4312     (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")
4313     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-named-block/11")
4314     (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-local-var-in-named-block/12")
4315     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-named-block/13")
4316     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-named-block/14")
4317     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-named-block/15")
4318     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-named-block/16")
4319     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-named-block/17")
4320     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-named-block/18")
4321     # . epilogue
4322     89/<- %esp 5/r32/ebp
4323     5d/pop-to-ebp
4324     c3/return
4326 test-unknown-variable-in-named-block:
4327     # . prologue
4328     55/push-ebp
4329     89/<- %ebp 4/r32/esp
4330     # setup
4331     (clear-stream _test-input-stream)
4332     (clear-stream $_test-input-buffered-file->buffer)
4333     (clear-stream _test-output-stream)
4334     (clear-stream $_test-output-buffered-file->buffer)
4335     (clear-stream _test-error-stream)
4336     (clear-stream $_test-error-buffered-file->buffer)
4337     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
4338     68/push 0/imm32
4339     68/push 0/imm32
4340     89/<- %edx 4/r32/esp
4341     (tailor-exit-descriptor %edx 0x10)
4342     #
4343     (write _test-input-stream "fn foo {\n")
4344     (write _test-input-stream "  $a: {\n")
4345     (write _test-input-stream "    compare x, 0\n")
4346     (write _test-input-stream "  }\n")
4347     (write _test-input-stream "}\n")
4348     # convert
4349     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
4350     # registers except esp clobbered at this point
4351     # restore ed
4352     89/<- %edx 4/r32/esp
4353     (flush _test-output-buffered-file)
4354     (flush _test-error-buffered-file)
4355 #?     # dump _test-error-stream {{{
4356 #?     (write 2 "^")
4357 #?     (write-stream 2 _test-error-stream)
4358 #?     (write 2 "$\n")
4359 #?     (rewind-stream _test-error-stream)
4360 #?     # }}}
4361     # check output
4362     (check-stream-equal _test-output-stream  ""  "F - test-unknown-variable-in-named-block: output should be empty")
4363     (check-next-stream-line-equal _test-error-stream  "fn foo: unknown variable 'x'"  "F - test-unknown-variable-in-named-block: error message")
4364     # check that stop(1) was called
4365     (check-ints-equal *(edx+4) 2 "F - test-unknown-variable-in-named-block: exit status")
4366     # don't restore from ebp
4367     81 0/subop/add %esp 8/imm32
4368     # . epilogue
4369     5d/pop-to-ebp
4370     c3/return
4372 test-always-shadow-outermost-reg-vars-in-function:
4373     # . prologue
4374     55/push-ebp
4375     89/<- %ebp 4/r32/esp
4376     # setup
4377     (clear-stream _test-input-stream)
4378     (clear-stream $_test-input-buffered-file->buffer)
4379     (clear-stream _test-output-stream)
4380     (clear-stream $_test-output-buffered-file->buffer)
4381     #
4382     (write _test-input-stream "fn foo {\n")
4383     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
4384     (write _test-input-stream "}\n")
4385     # convert
4386     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
4387     (flush _test-output-buffered-file)
4388 #?     # dump _test-output-stream {{{
4389 #?     (write 2 "^")
4390 #?     (write-stream 2 _test-output-stream)
4391 #?     (write 2 "$\n")
4392 #?     (rewind-stream _test-output-stream)
4393 #?     # }}}
4394     # check output
4395     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-always-shadow-outermost-reg-vars-in-function/0")
4396     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-always-shadow-outermost-reg-vars-in-function/1")
4397     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-always-shadow-outermost-reg-vars-in-function/2")
4398     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-always-shadow-outermost-reg-vars-in-function/3")
4399     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-always-shadow-outermost-reg-vars-in-function/4")
4400     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-always-shadow-outermost-reg-vars-in-function/5")
4401     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
4402     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-always-shadow-outermost-reg-vars-in-function/8")
4403     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
4404     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-always-shadow-outermost-reg-vars-in-function/12")
4405     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-always-shadow-outermost-reg-vars-in-function/13")
4406     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-always-shadow-outermost-reg-vars-in-function/14")
4407     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-always-shadow-outermost-reg-vars-in-function/15")
4408     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-always-shadow-outermost-reg-vars-in-function/16")
4409     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-always-shadow-outermost-reg-vars-in-function/17")
4410     # . epilogue
4411     89/<- %esp 5/r32/ebp
4412     5d/pop-to-ebp
4413     c3/return
4415 test-shadow-local:
4416     # . prologue
4417     55/push-ebp
4418     89/<- %ebp 4/r32/esp
4419     # setup
4420     (clear-stream _test-input-stream)
4421     (clear-stream $_test-input-buffered-file->buffer)
4422     (clear-stream _test-output-stream)
4423     (clear-stream $_test-output-buffered-file->buffer)
4424     #
4425     (write _test-input-stream "fn foo {\n")
4426     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
4427     (write _test-input-stream "  {\n")
4428     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
4429     (write _test-input-stream "  }\n")
4430     (write _test-input-stream "  x <- increment\n")
4431     (write _test-input-stream "}\n")
4432     # convert
4433     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
4434     (flush _test-output-buffered-file)
4435 #?     # dump _test-output-stream {{{
4436 #?     (write 2 "^")
4437 #?     (write-stream 2 _test-output-stream)
4438 #?     (write 2 "$\n")
4439 #?     (rewind-stream _test-output-stream)
4440 #?     # }}}
4441     # check output
4442     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-local/0")
4443     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-local/1")
4444     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-local/2")
4445     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-local/3")
4446     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-local/4")
4447     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-local/5")
4448     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-local/6")
4449     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-local/7")
4450     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-local/8")
4451     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-local/9")
4452     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-local/10")
4453     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-local/11")
4454     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-local/12")
4455     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-local/13")
4456     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-local/14")
4457     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-local/15")
4458     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-local/16")
4459     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-local/17")
4460     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-local/18")
4461     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-local/19")
4462     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-local/20")
4463     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-local/21")
4464     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-local/22")
4465     # . epilogue
4466     89/<- %esp 5/r32/ebp
4467     5d/pop-to-ebp
4468     c3/return
4470 test-shadow-name:
4471     # . prologue
4472     55/push-ebp
4473     89/<- %ebp 4/r32/esp
4474     # setup
4475     (clear-stream _test-input-stream)
4476     (clear-stream $_test-input-buffered-file->buffer)
4477     (clear-stream _test-output-stream)
4478     (clear-stream $_test-output-buffered-file->buffer)
4479     #
4480     (write _test-input-stream "fn foo {\n")
4481     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
4482     (write _test-input-stream "  {\n")
4483     (write _test-input-stream "    var x/edx: int <- copy 4\n")
4484     (write _test-input-stream "  }\n")
4485     (write _test-input-stream "  x <- increment\n")
4486     (write _test-input-stream "}\n")
4487     # convert
4488     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
4489     (flush _test-output-buffered-file)
4490 #?     # dump _test-output-stream {{{
4491 #?     (write 2 "^")
4492 #?     (write-stream 2 _test-output-stream)
4493 #?     (write 2 "$\n")
4494 #?     (rewind-stream _test-output-stream)
4495 #?     # }}}
4496     # check output
4497     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-name/0")
4498     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-name/1")
4499     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-name/2")
4500     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-name/3")
4501     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-name/4")
4502     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-name/5")
4503     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-name/6")
4504     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-name/7")
4505     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-name/8")
4506     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-name/9")
4507     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %edx"  "F - test-shadow-name/10")
4508     (check-next-stream-line-equal _test-output-stream "      ba/copy-to-edx 4/imm32"  "F - test-shadow-name/11")
4509     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %edx" "F - test-shadow-name/12")
4510     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-name/13")
4511     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-name/14")
4512     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-name/15")
4513     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-name/16")
4514     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-name/17")
4515     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-name/18")
4516     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-name/19")
4517     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-name/20")
4518     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-name/21")
4519     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-name/22")
4520     # . epilogue
4521     89/<- %esp 5/r32/ebp
4522     5d/pop-to-ebp
4523     c3/return
4525 test-shadow-name-2:
4526     # . prologue
4527     55/push-ebp
4528     89/<- %ebp 4/r32/esp
4529     # setup
4530     (clear-stream _test-input-stream)
4531     (clear-stream $_test-input-buffered-file->buffer)
4532     (clear-stream _test-output-stream)
4533     (clear-stream $_test-output-buffered-file->buffer)
4534     #
4535     (write _test-input-stream "fn foo {\n")
4536     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
4537     (write _test-input-stream "  {\n")
4538     (write _test-input-stream "    var x/edx: int <- copy 4\n")
4539     (write _test-input-stream "    var y/ecx: int <- copy 5\n")
4540     (write _test-input-stream "  }\n")
4541     (write _test-input-stream "  x <- increment\n")
4542     (write _test-input-stream "}\n")
4543     # convert
4544     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
4545     (flush _test-output-buffered-file)
4546 #?     # dump _test-output-stream {{{
4547 #?     (write 2 "^")
4548 #?     (write-stream 2 _test-output-stream)
4549 #?     (write 2 "$\n")
4550 #?     (rewind-stream _test-output-stream)
4551 #?     # }}}
4552     # check output
4553     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-name-2/0")
4554     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-name-2/1")
4555     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-name-2/2")
4556     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-name-2/3")
4557     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-name-2/4")
4558     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-name-2/5")
4559     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-name-2/6")
4560     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-name-2/7")
4561     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-name-2/8")
4562     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-name-2/9")
4563     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %edx"  "F - test-shadow-name-2/10")
4564     (check-next-stream-line-equal _test-output-stream "      ba/copy-to-edx 4/imm32"  "F - test-shadow-name-2/11")
4565     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-name-2/12")
4566     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 5/imm32"  "F - test-shadow-name-2/13")
4567     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-name-2/14")
4568     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %edx" "F - test-shadow-name-2/15")
4569     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-name-2/16")
4570     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-name-2/17")
4571     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-name-2/18")
4572     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-name-2/19")
4573     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-name-2/20")
4574     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-name-2/21")
4575     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-name-2/22")
4576     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-name-2/23")
4577     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-name-2/24")
4578     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-name-2/25")
4579     # . epilogue
4580     89/<- %esp 5/r32/ebp
4581     5d/pop-to-ebp
4582     c3/return
4584 test-do-not-spill-same-register-in-block:
4585     # . prologue
4586     55/push-ebp
4587     89/<- %ebp 4/r32/esp
4588     # setup
4589     (clear-stream _test-input-stream)
4590     (clear-stream $_test-input-buffered-file->buffer)
4591     (clear-stream _test-output-stream)
4592     (clear-stream $_test-output-buffered-file->buffer)
4593     #
4594     (write _test-input-stream "fn foo {\n")
4595     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
4596     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
4597     (write _test-input-stream "  y <- increment\n")
4598     (write _test-input-stream "}\n")
4599     # convert
4600     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
4601     (flush _test-output-buffered-file)
4602 #?     # dump _test-output-stream {{{
4603 #?     (write 2 "^")
4604 #?     (write-stream 2 _test-output-stream)
4605 #?     (write 2 "$\n")
4606 #?     (rewind-stream _test-output-stream)
4607 #?     # }}}
4608     # check output
4609     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-do-not-spill-same-register-in-block/0")
4610     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-do-not-spill-same-register-in-block/1")
4611     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-do-not-spill-same-register-in-block/2")
4612     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-do-not-spill-same-register-in-block/3")
4613     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-do-not-spill-same-register-in-block/4")
4614     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-do-not-spill-same-register-in-block/5")
4615     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-do-not-spill-same-register-in-block/6")
4616     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-do-not-spill-same-register-in-block/7")
4617     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-do-not-spill-same-register-in-block/8")
4618     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-do-not-spill-same-register-in-block/9")
4619     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-do-not-spill-same-register-in-block/10")
4620     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-do-not-spill-same-register-in-block/11")
4621     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-do-not-spill-same-register-in-block/12")
4622     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-do-not-spill-same-register-in-block/13")
4623     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-do-not-spill-same-register-in-block/14")
4624     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-do-not-spill-same-register-in-block/15")
4625     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-do-not-spill-same-register-in-block/16")
4626     # . epilogue
4627     89/<- %esp 5/r32/ebp
4628     5d/pop-to-ebp
4629     c3/return
4631 test-spill-different-register-in-block:
4632     # . prologue
4633     55/push-ebp
4634     89/<- %ebp 4/r32/esp
4635     # setup
4636     (clear-stream _test-input-stream)
4637     (clear-stream $_test-input-buffered-file->buffer)
4638     (clear-stream _test-output-stream)
4639     (clear-stream $_test-output-buffered-file->buffer)
4640     #
4641     (write _test-input-stream "fn foo {\n")
4642     (write _test-input-stream "  var x/eax: int <- copy 3\n")
4643     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
4644     (write _test-input-stream "  y <- increment\n")
4645     (write _test-input-stream "}\n")
4646     # convert
4647     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
4648     (flush _test-output-buffered-file)
4649 #?     # dump _test-output-stream {{{
4650 #?     (write 2 "^")
4651 #?     (write-stream 2 _test-output-stream)
4652 #?     (write 2 "$\n")
4653 #?     (rewind-stream _test-output-stream)
4654 #?     # }}}
4655     # check output
4656     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-spill-different-register-in-block/0")
4657     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-spill-different-register-in-block/1")
4658     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-spill-different-register-in-block/2")
4659     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-spill-different-register-in-block/3")
4660     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-spill-different-register-in-block/4")
4661     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-spill-different-register-in-block/5")
4662     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-spill-different-register-in-block/6")
4663     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-spill-different-register-in-block/7")
4664     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-spill-different-register-in-block/8")
4665     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-spill-different-register-in-block/9")
4666     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-spill-different-register-in-block/10")
4667     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-spill-different-register-in-block/11")
4668     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-spill-different-register-in-block/12")
4669     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-spill-different-register-in-block/13")
4670     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-spill-different-register-in-block/14")
4671     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-spill-different-register-in-block/15")
4672     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-spill-different-register-in-block/16")
4673     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-spill-different-register-in-block/17")
4674     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-spill-different-register-in-block/18")
4675     # . epilogue
4676     89/<- %esp 5/r32/ebp
4677     5d/pop-to-ebp
4678     c3/return
4680 test-convert-function-with-branches-in-block:
4681     # . prologue
4682     55/push-ebp
4683     89/<- %ebp 4/r32/esp
4684     # setup
4685     (clear-stream _test-input-stream)
4686     (clear-stream $_test-input-buffered-file->buffer)
4687     (clear-stream _test-output-stream)
4688     (clear-stream $_test-output-buffered-file->buffer)
4689     #
4690     (write _test-input-stream "fn foo x: int {\n")
4691     (write _test-input-stream "  {\n")
4692     (write _test-input-stream "    break-if->=\n")
4693     (write _test-input-stream "    loop-if-addr<\n")
4694     (write _test-input-stream "    increment x\n")
4695     (write _test-input-stream "    loop\n")
4696     (write _test-input-stream "  }\n")
4697     (write _test-input-stream "}\n")
4698     # convert
4699     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
4700     (flush _test-output-buffered-file)
4701 #?     # dump _test-output-stream {{{
4702 #?     (write 2 "^")
4703 #?     (write-stream 2 _test-output-stream)
4704 #?     (write 2 "$\n")
4705 #?     (rewind-stream _test-output-stream)
4706 #?     # }}}
4707     # check output
4708     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-block/0")
4709     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-block/1")
4710     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-block/2")
4711     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-block/3")
4712     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-block/4")
4713     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-block/5")
4714     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-block/6")
4715     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-in-block/7")
4716     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/8")
4717     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-block/9")
4718     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-in-block/10")
4719     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/11")
4720     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/12")
4721     (check-next-stream-line-equal _test-output-stream "        0f 83/jump-if-addr>= break/disp32"  "F - test-convert-function-with-branches-in-block/13")
4722     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:loop/disp32"  "F - test-convert-function-with-branches-in-block/14")
4723     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/15")
4724     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-block/16")
4725     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-in-block/17")
4726     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-block/18")
4727     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-in-block/19")
4728     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-block/20")
4729     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-block/21")
4730     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-block/22")
4731     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-block/23")
4732     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-block/24")
4733     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-block/25")
4734     # . epilogue
4735     89/<- %esp 5/r32/ebp
4736     5d/pop-to-ebp
4737     c3/return
4739 test-convert-function-with-branches-in-block-2:
4740     # . prologue
4741     55/push-ebp
4742     89/<- %ebp 4/r32/esp
4743     # setup
4744     (clear-stream _test-input-stream)
4745     (clear-stream $_test-input-buffered-file->buffer)
4746     (clear-stream _test-output-stream)
4747     (clear-stream $_test-output-buffered-file->buffer)
4748     #
4749     (write _test-input-stream "fn foo x: int {\n")
4750     (write _test-input-stream "  {\n")
4751     (write _test-input-stream "    break-if->=\n")
4752     (write _test-input-stream "    loop-if-float<\n")
4753     (write _test-input-stream "    increment x\n")
4754     (write _test-input-stream "    loop\n")
4755     (write _test-input-stream "  }\n")
4756     (write _test-input-stream "}\n")
4757     # convert
4758     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
4759     (flush _test-output-buffered-file)
4760 #?     # dump _test-output-stream {{{
4761 #?     (write 2 "^")
4762 #?     (write-stream 2 _test-output-stream)
4763 #?     (write 2 "$\n")
4764 #?     (rewind-stream _test-output-stream)
4765 #?     # }}}
4766     # check output
4767     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-block/0")
4768     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-block/1")
4769     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-block/2")
4770     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-block/3")
4771     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-block/4")
4772     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-block/5")
4773     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-block/6")
4774     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-in-block/7")
4775     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/8")
4776     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-block/9")
4777     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-in-block/10")
4778     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/11")
4779     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/12")
4780     (check-next-stream-line-equal _test-output-stream "        0f 83/jump-if-addr>= break/disp32"  "F - test-convert-function-with-branches-in-block/13")
4781     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:loop/disp32"  "F - test-convert-function-with-branches-in-block/14")
4782     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/15")
4783     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-block/16")
4784     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-in-block/17")
4785     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-block/18")
4786     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-in-block/19")
4787     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-block/20")
4788     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-block/21")
4789     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-block/22")
4790     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-block/23")
4791     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-block/24")
4792     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-block/25")
4793     # . epilogue
4794     89/<- %esp 5/r32/ebp
4795     5d/pop-to-ebp
4796     c3/return
4798 test-convert-function-with-branches-in-named-block:
4799     # . prologue
4800     55/push-ebp
4801     89/<- %ebp 4/r32/esp
4802     # setup
4803     (clear-stream _test-input-stream)
4804     (clear-stream $_test-input-buffered-file->buffer)
4805     (clear-stream _test-output-stream)
4806     (clear-stream $_test-output-buffered-file->buffer)
4807     #
4808     (write _test-input-stream "fn foo x: int {\n")
4809     (write _test-input-stream "  $bar: {\n")
4810     (write _test-input-stream "    break-if->= $bar\n")
4811     (write _test-input-stream "    loop-if-addr< $bar\n")
4812     (write _test-input-stream "    increment x\n")
4813     (write _test-input-stream "    loop\n")
4814     (write _test-input-stream "  }\n")
4815     (write _test-input-stream "}\n")
4816     # convert
4817     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
4818     (flush _test-output-buffered-file)
4819 #?     # dump _test-output-stream {{{
4820 #?     (write 2 "^")
4821 #?     (write-stream 2 _test-output-stream)
4822 #?     (write 2 "$\n")
4823 #?     (rewind-stream _test-output-stream)
4824 #?     # }}}
4825     # check output
4826     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-named-block/0")
4827     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-named-block/1")
4828     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-named-block/2")
4829     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-named-block/3")
4830     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-named-block/4")
4831     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-named-block/5")
4832     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-named-block/6")
4833     (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-branches-in-named-block/7")
4834     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-named-block/8")
4835     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-named-block/9")
4836     (check-next-stream-line-equal _test-output-stream "        e9/jump $bar:break/disp32"  "F - test-convert-function-with-branches-in-named-block/10")
4837     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-named-block/11")
4838     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-named-block/12")
4839     (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")
4840     (check-next-stream-line-equal _test-output-stream "        e9/jump $bar:loop/disp32"  "F - test-convert-function-with-branches-in-named-block/14")
4841     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-named-block/15")
4842     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-named-block/16")
4843     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"   "F - test-convert-function-with-branches-in-named-block/17")
4844     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-named-block/18")
4845     (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-branches-in-named-block/19")
4846     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-named-block/20")
4847     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-named-block/21")
4848     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-named-block/22")
4849     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-named-block/23")
4850     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-named-block/24")
4851     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-named-block/25")
4852     # . epilogue
4853     89/<- %esp 5/r32/ebp
4854     5d/pop-to-ebp
4855     c3/return
4857 test-convert-function-with-var-in-nested-block:
4858     # . prologue
4859     55/push-ebp
4860     89/<- %ebp 4/r32/esp
4861     # setup
4862     (clear-stream _test-input-stream)
4863     (clear-stream $_test-input-buffered-file->buffer)
4864     (clear-stream _test-output-stream)
4865     (clear-stream $_test-output-buffered-file->buffer)
4866     #
4867     (write _test-input-stream "fn foo x: int {\n")
4868     (write _test-input-stream "  {\n")
4869     (write _test-input-stream "    {\n")
4870     (write _test-input-stream "      var x: int\n")
4871     (write _test-input-stream "      increment x\n")
4872     (write _test-input-stream "    }\n")
4873     (write _test-input-stream "  }\n")
4874     (write _test-input-stream "}\n")
4875     # convert
4876     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
4877     (flush _test-output-buffered-file)
4878 #?     # dump _test-output-stream {{{
4879 #?     (write 2 "^")
4880 #?     (write-stream 2 _test-output-stream)
4881 #?     (write 2 "$\n")
4882 #?     (rewind-stream _test-output-stream)
4883 #?     # }}}
4884     # check output
4885     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-var-in-nested-block/0")
4886     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-var-in-nested-block/1")
4887     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-var-in-nested-block/2")
4888     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-var-in-nested-block/3")
4889     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-var-in-nested-block/4")
4890     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-var-in-nested-block/5")
4891     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-var-in-nested-block/6")
4892     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-var-in-nested-block/7")
4893     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-var-in-nested-block/8")
4894     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-var-in-nested-block/9")
4895     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-var-in-nested-block/10")
4896     (check-next-stream-line-equal _test-output-stream "        ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-var-in-nested-block/11")
4897     (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")
4898     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-var-in-nested-block/13")
4899     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-var-in-nested-block/14")
4900     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-var-in-nested-block/15")
4901     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-var-in-nested-block/16")
4902     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-var-in-nested-block/17")
4903     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-var-in-nested-block/18")
4904     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-var-in-nested-block/19")
4905     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-var-in-nested-block/20")
4906     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-var-in-nested-block/21")
4907     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-var-in-nested-block/22")
4908     # . epilogue
4909     89/<- %esp 5/r32/ebp
4910     5d/pop-to-ebp
4911     c3/return
4913 test-convert-function-with-multiple-vars-in-nested-blocks:
4914     # . prologue
4915     55/push-ebp
4916     89/<- %ebp 4/r32/esp
4917     # setup
4918     (clear-stream _test-input-stream)
4919     (clear-stream $_test-input-buffered-file->buffer)
4920     (clear-stream _test-output-stream)
4921     (clear-stream $_test-output-buffered-file->buffer)
4922     #
4923     (write _test-input-stream "fn foo x: int {\n")
4924     (write _test-input-stream "  {\n")
4925     (write _test-input-stream "    var x/eax: int <- copy 0\n")
4926     (write _test-input-stream "    {\n")
4927     (write _test-input-stream "      var y: int\n")
4928     (write _test-input-stream "      x <- add y\n")
4929     (write _test-input-stream "    }\n")
4930     (write _test-input-stream "  }\n")
4931     (write _test-input-stream "}\n")
4932     # convert
4933     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
4934     (flush _test-output-buffered-file)
4935 #?     # dump _test-output-stream {{{
4936 #?     (write 2 "^")
4937 #?     (write-stream 2 _test-output-stream)
4938 #?     (write 2 "$\n")
4939 #?     (rewind-stream _test-output-stream)
4940 #?     # }}}
4941     # check output
4942     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-multiple-vars-in-nested-blocks/0")
4943     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/1")
4944     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-multiple-vars-in-nested-blocks/2")
4945     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/3")
4946     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/4")
4947     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/5")
4948     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/6")
4949     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/7")
4950     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %eax"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/8")
4951     (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")
4952     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/10")
4953     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/11")
4954     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-multiple-vars-in-nested-blocks/12")
4955     (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")
4956     (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")
4957     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/15")
4958     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/16")
4959     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %eax"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/17")
4960     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/18")
4961     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/19")
4962     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/20")
4963     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/21")
4964     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/22")
4965     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/23")
4966     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-multiple-vars-in-nested-blocks/24")
4967     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-multiple-vars-in-nested-blocks/25")
4968     # . epilogue
4969     89/<- %esp 5/r32/ebp
4970     5d/pop-to-ebp
4971     c3/return
4973 test-convert-function-with-branches-and-local-vars:
4974     # A conditional 'break' after a 'var' in a block is converted into a
4975     # nested block that performs all necessary cleanup before jumping. This
4976     # results in some ugly code duplication.
4977     # . prologue
4978     55/push-ebp
4979     89/<- %ebp 4/r32/esp
4980     # setup
4981     (clear-stream _test-input-stream)
4982     (clear-stream $_test-input-buffered-file->buffer)
4983     (clear-stream _test-output-stream)
4984     (clear-stream $_test-output-buffered-file->buffer)
4985     #
4986     (write _test-input-stream "fn foo {\n")
4987     (write _test-input-stream "  {\n")
4988     (write _test-input-stream "    var x: int\n")
4989     (write _test-input-stream "    break-if->=\n")
4990     (write _test-input-stream "    increment x\n")
4991     (write _test-input-stream "  }\n")
4992     (write _test-input-stream "}\n")
4993     # convert
4994     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
4995     (flush _test-output-buffered-file)
4996 #?     # dump _test-output-stream {{{
4997 #?     (write 2 "^")
4998 #?     (write-stream 2 _test-output-stream)
4999 #?     (write 2 "$\n")
5000 #?     (rewind-stream _test-output-stream)
5001 #?     # }}}
5002     # check output
5003     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-local-vars/0")
5004     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-local-vars/1")
5005     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-local-vars/2")
5006     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-and-local-vars/3")
5007     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-local-vars/4")
5008     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-local-vars/5")
5009     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-local-vars/6")
5010     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-local-vars/7")
5011     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-local-vars/8")
5012     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-local-vars/9")
5013     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-and-local-vars/10")
5014     (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")
5015     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-and-local-vars/12")
5016     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-local-vars/13")
5017     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-branches-and-local-vars/14")
5018     (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")
5019     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-local-vars/16")
5020     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-local-vars/17")
5021     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-local-vars/18")
5022     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-local-vars/19")
5023     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-local-vars/20")
5024     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-and-local-vars/21")
5025     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-local-vars/22")
5026     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-local-vars/23")
5027     # . epilogue
5028     89/<- %esp 5/r32/ebp
5029     5d/pop-to-ebp
5030     c3/return
5032 test-convert-function-with-conditional-loops-and-local-vars:
5033     # A conditional 'loop' after a 'var' in a block is converted into a nested
5034     # block that performs all necessary cleanup before jumping. This results
5035     # in some ugly code duplication.
5036     # . prologue
5037     55/push-ebp
5038     89/<- %ebp 4/r32/esp
5039     # setup
5040     (clear-stream _test-input-stream)
5041     (clear-stream $_test-input-buffered-file->buffer)
5042     (clear-stream _test-output-stream)
5043     (clear-stream $_test-output-buffered-file->buffer)
5044     #
5045     (write _test-input-stream "fn foo {\n")
5046     (write _test-input-stream "  {\n")
5047     (write _test-input-stream "    var x: int\n")
5048     (write _test-input-stream "    loop-if->=\n")
5049     (write _test-input-stream "    increment x\n")
5050     (write _test-input-stream "  }\n")
5051     (write _test-input-stream "}\n")
5052     # convert
5053     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
5054     (flush _test-output-buffered-file)
5055 #?     # dump _test-output-stream {{{
5056 #?     (write 2 "^")
5057 #?     (write-stream 2 _test-output-stream)
5058 #?     (write 2 "$\n")
5059 #?     (rewind-stream _test-output-stream)
5060 #?     # }}}
5061     # check output
5062     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-conditional-loops-and-local-vars/0")
5063     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-conditional-loops-and-local-vars/1")
5064     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-conditional-loops-and-local-vars/2")
5065     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-conditional-loops-and-local-vars/3")
5066     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-conditional-loops-and-local-vars/4")
5067     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/5")
5068     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-conditional-loops-and-local-vars/6")
5069     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/7")
5070     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-conditional-loops-and-local-vars/8")
5071     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-conditional-loops-and-local-vars/9")
5072     (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")
5073     (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")
5074     (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")
5075     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-conditional-loops-and-local-vars/13")
5076     (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")
5077     (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")
5078     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-conditional-loops-and-local-vars/16")
5079     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/17")
5080     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-conditional-loops-and-local-vars/18")
5081     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/19")
5082     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-conditional-loops-and-local-vars/20")
5083     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-conditional-loops-and-local-vars/21")
5084     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-conditional-loops-and-local-vars/22")
5085     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-conditional-loops-and-local-vars/23")
5086     # . epilogue
5087     89/<- %esp 5/r32/ebp
5088     5d/pop-to-ebp
5089     c3/return
5091 test-convert-function-with-unconditional-loops-and-local-vars:
5092     # An unconditional 'loop' after a 'var' in a block is emitted _after_ the
5093     # regular block cleanup. Any instructions after 'loop' are dead and
5094     # therefore skipped.
5095     # . prologue
5096     55/push-ebp
5097     89/<- %ebp 4/r32/esp
5098     # setup
5099     (clear-stream _test-input-stream)
5100     (clear-stream $_test-input-buffered-file->buffer)
5101     (clear-stream _test-output-stream)
5102     (clear-stream $_test-output-buffered-file->buffer)
5103     #
5104     (write _test-input-stream "fn foo {\n")
5105     (write _test-input-stream "  {\n")
5106     (write _test-input-stream "    var x: int\n")
5107     (write _test-input-stream "    loop\n")
5108     (write _test-input-stream "    increment x\n")
5109     (write _test-input-stream "  }\n")
5110     (write _test-input-stream "}\n")
5111     # convert
5112     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
5113     (flush _test-output-buffered-file)
5114 #?     # dump _test-output-stream {{{
5115 #?     (write 2 "^")
5116 #?     (write-stream 2 _test-output-stream)
5117 #?     (write 2 "$\n")
5118 #?     (rewind-stream _test-output-stream)
5119 #?     # }}}
5120     # check output
5121     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-loops-and-local-vars/0")
5122     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/1")
5123     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-loops-and-local-vars/2")
5124     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/3")
5125     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/4")
5126     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/5")
5127     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/6")
5128     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/7")
5129     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-loops-and-local-vars/8")
5130     (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")
5131     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-unconditional-loops-and-local-vars/10")
5132     # not emitted:                                           ff 0/subop/increment *(ebp+0xfffffffc)
5133     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/11")
5134     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/12")
5135     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/13")
5136     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/14")
5137     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/15")
5138     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/16")
5139     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-loops-and-local-vars/17")
5140     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-loops-and-local-vars/18")
5141     # . epilogue
5142     89/<- %esp 5/r32/ebp
5143     5d/pop-to-ebp
5144     c3/return
5146 test-convert-function-with-branches-and-loops-and-local-vars:
5147     # . prologue
5148     55/push-ebp
5149     89/<- %ebp 4/r32/esp
5150     # setup
5151     (clear-stream _test-input-stream)
5152     (clear-stream $_test-input-buffered-file->buffer)
5153     (clear-stream _test-output-stream)
5154     (clear-stream $_test-output-buffered-file->buffer)
5155     #
5156     (write _test-input-stream "fn foo {\n")
5157     (write _test-input-stream "  {\n")
5158     (write _test-input-stream "    var x: int\n")
5159     (write _test-input-stream "    break-if->=\n")
5160     (write _test-input-stream "    increment x\n")
5161     (write _test-input-stream "    loop\n")
5162     (write _test-input-stream "  }\n")
5163     (write _test-input-stream "}\n")
5164     # convert
5165     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
5166     (flush _test-output-buffered-file)
5167 #?     # dump _test-output-stream {{{
5168 #?     (write 2 "^")
5169 #?     (write-stream 2 _test-output-stream)
5170 #?     (write 2 "$\n")
5171 #?     (rewind-stream _test-output-stream)
5172 #?     # }}}
5173     # check output
5174     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-loops-and-local-vars/0")
5175     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/1")
5176     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-loops-and-local-vars/2")
5177     (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")
5178     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/4")
5179     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/5")
5180     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/6")
5181     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/7")
5182     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-loops-and-local-vars/8")
5183     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/9")
5184     (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")
5185     (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")
5186     (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")
5187     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/13")
5188     (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")
5189     (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")
5190     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-and-loops-and-local-vars/16")
5191     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/17")
5192     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/18")
5193     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/19")
5194     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/20")
5195     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/21")
5196     (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")
5197     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-loops-and-local-vars/23")
5198     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-loops-and-local-vars/24")
5199     # . epilogue
5200     89/<- %esp 5/r32/ebp
5201     5d/pop-to-ebp
5202     c3/return
5204 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars:
5205     # . prologue
5206     55/push-ebp
5207     89/<- %ebp 4/r32/esp
5208     # setup
5209     (clear-stream _test-input-stream)
5210     (clear-stream $_test-input-buffered-file->buffer)
5211     (clear-stream _test-output-stream)
5212     (clear-stream $_test-output-buffered-file->buffer)
5213     #
5214     (write _test-input-stream "fn foo {\n")
5215     (write _test-input-stream "  a: {\n")
5216     (write _test-input-stream "    var x: int\n")
5217     (write _test-input-stream "    {\n")
5218     (write _test-input-stream "      var y: int\n")
5219     (write _test-input-stream "      break-if->= a\n")
5220     (write _test-input-stream "      increment x\n")
5221     (write _test-input-stream "      loop\n")
5222     (write _test-input-stream "    }\n")
5223     (write _test-input-stream "  }\n")
5224     (write _test-input-stream "}\n")
5225     # convert
5226     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
5227     (flush _test-output-buffered-file)
5228 #?     # dump _test-output-stream {{{
5229 #?     (write 2 "^")
5230 #?     (write-stream 2 _test-output-stream)
5231 #?     (write 2 "$\n")
5232 #?     (rewind-stream _test-output-stream)
5233 #?     # }}}
5234     # check output
5235     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/0")
5236     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/1")
5237     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/2")
5238     (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")
5239     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/4")
5240     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/5")
5241     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/6")
5242     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/7")
5243     (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")
5244     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/9")
5245     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/10")
5246     (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")
5247     (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/12")
5248     (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")
5249     (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")
5250     (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")
5251     (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")
5252     (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/17")
5253     (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")
5254     (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")
5255     (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")
5256     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/21")
5257     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/22")
5258     (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")
5259     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/24")
5260     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/25")
5261     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/26")
5262     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/27")
5263     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/28")
5264     (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")
5265     (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")
5266     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/31")
5267     # . epilogue
5268     89/<- %esp 5/r32/ebp
5269     5d/pop-to-ebp
5270     c3/return
5272 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2:
5273     # . prologue
5274     55/push-ebp
5275     89/<- %ebp 4/r32/esp
5276     # setup
5277     (clear-stream _test-input-stream)
5278     (clear-stream $_test-input-buffered-file->buffer)
5279     (clear-stream _test-output-stream)
5280     (clear-stream $_test-output-buffered-file->buffer)
5281     # non-local conditional branch from a block without a local variable,
5282     # unwinding a local on the stack
5283     (write _test-input-stream "fn foo {\n")
5284     (write _test-input-stream "  a: {\n")
5285     (write _test-input-stream "    var x: int\n")
5286     (write _test-input-stream "    {\n")
5287     (write _test-input-stream "      break-if->= a\n")
5288     (write _test-input-stream "    }\n")
5289     (write _test-input-stream "  }\n")
5290     (write _test-input-stream "}\n")
5291     # convert
5292     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
5293     (flush _test-output-buffered-file)
5294 #?     # dump _test-output-stream {{{
5295 #?     (write 2 "^")
5296 #?     (write-stream 2 _test-output-stream)
5297 #?     (write 2 "$\n")
5298 #?     (rewind-stream _test-output-stream)
5299 #?     # }}}
5300     # check output
5301     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/0")
5302     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/1")
5303     (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")
5304     (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")
5305     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/4")
5306     (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")
5307     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/6")
5308     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/7")
5309     (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")
5310     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/9")
5311     (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")
5312     (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/11")
5313     (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")
5314     (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")
5315     (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")
5316     (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/15")
5317     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/16")
5318     (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")
5319     (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")
5320     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/19")
5321     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/20")
5322     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/21")
5323     (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")
5324     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/23")
5325     (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")
5326     (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")
5327     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/26")
5328     # . epilogue
5329     89/<- %esp 5/r32/ebp
5330     5d/pop-to-ebp
5331     c3/return
5333 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3:
5334     # . prologue
5335     55/push-ebp
5336     89/<- %ebp 4/r32/esp
5337     # setup
5338     (clear-stream _test-input-stream)
5339     (clear-stream $_test-input-buffered-file->buffer)
5340     (clear-stream _test-output-stream)
5341     (clear-stream $_test-output-buffered-file->buffer)
5342     # non-local unconditional branch from a block without a local variable,
5343     # unwinding a local on the stack
5344     (write _test-input-stream "fn foo {\n")
5345     (write _test-input-stream "  a: {\n")
5346     (write _test-input-stream "    var x: int\n")
5347     (write _test-input-stream "    {\n")
5348     (write _test-input-stream "      break a\n")
5349     (write _test-input-stream "    }\n")
5350     (write _test-input-stream "  }\n")
5351     (write _test-input-stream "}\n")
5352     # convert
5353     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
5354     (flush _test-output-buffered-file)
5355 #?     # dump _test-output-stream {{{
5356 #?     (write 2 "^")
5357 #?     (write-stream 2 _test-output-stream)
5358 #?     (write 2 "$\n")
5359 #?     (rewind-stream _test-output-stream)
5360 #?     # }}}
5361     # check output
5362     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/0")
5363     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/1")
5364     (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")
5365     (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")
5366     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/4")
5367     (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")
5368     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/6")
5369     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/7")
5370     (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")
5371     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/9")
5372     (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")
5373     (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")
5374     (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")
5375     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/14")
5376     (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")
5377     (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")
5378     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/17")
5379     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/18")
5380     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/19")
5381     (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")
5382     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/21")
5383     (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")
5384     (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")
5385     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/24")
5386     # . epilogue
5387     89/<- %esp 5/r32/ebp
5388     5d/pop-to-ebp
5389     c3/return
5391 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4:
5392     # . prologue
5393     55/push-ebp
5394     89/<- %ebp 4/r32/esp
5395     # setup
5396     (clear-stream _test-input-stream)
5397     (clear-stream $_test-input-buffered-file->buffer)
5398     (clear-stream _test-output-stream)
5399     (clear-stream $_test-output-buffered-file->buffer)
5400     #
5401     (write _test-input-stream "fn foo {\n")
5402     (write _test-input-stream "  a: {\n")
5403     (write _test-input-stream "    var x/esi: int <- copy 0\n")
5404     (write _test-input-stream "    {\n")
5405     (write _test-input-stream "      break a\n")
5406     (write _test-input-stream "    }\n")
5407     (write _test-input-stream "  }\n")
5408     (write _test-input-stream "}\n")
5409     # convert
5410     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
5411     (flush _test-output-buffered-file)
5412 #?     # dump _test-output-stream {{{
5413 #?     (write 2 "^")
5414 #?     (write-stream 2 _test-output-stream)
5415 #?     (write 2 "$\n")
5416 #?     (rewind-stream _test-output-stream)
5417 #?     # }}}
5418     # check output
5419     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/0")
5420     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/1")
5421     (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")
5422     (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")
5423     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/4")
5424     (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")
5425     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/6")
5426     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/7")
5427     (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")
5428     (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")
5429     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/10")
5430     (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")
5431     (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")
5432     (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")
5433     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/14")
5434     (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")
5435     (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")
5436     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/17")
5437     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/18")
5438     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/19")
5439     (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")
5440     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/21")
5441     (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")
5442     (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")
5443     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/24")
5444     # . epilogue
5445     89/<- %esp 5/r32/ebp
5446     5d/pop-to-ebp
5447     c3/return
5449 test-convert-function-with-nonlocal-unconditional-break-and-local-vars:
5450     # . prologue
5451     55/push-ebp
5452     89/<- %ebp 4/r32/esp
5453     # setup
5454     (clear-stream _test-input-stream)
5455     (clear-stream $_test-input-buffered-file->buffer)
5456     (clear-stream _test-output-stream)
5457     (clear-stream $_test-output-buffered-file->buffer)
5458     #
5459     (write _test-input-stream "fn foo {\n")
5460     (write _test-input-stream "  a: {\n")
5461     (write _test-input-stream "    var x: int\n")
5462     (write _test-input-stream "    {\n")
5463     (write _test-input-stream "      var y: int\n")
5464     (write _test-input-stream "      break a\n")
5465     (write _test-input-stream "      increment x\n")
5466     (write _test-input-stream "    }\n")
5467     (write _test-input-stream "  }\n")
5468     (write _test-input-stream "}\n")
5469     # convert
5470     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
5471     (flush _test-output-buffered-file)
5472 #?     # dump _test-output-stream {{{
5473 #?     (write 2 "^")
5474 #?     (write-stream 2 _test-output-stream)
5475 #?     (write 2 "$\n")
5476 #?     (rewind-stream _test-output-stream)
5477 #?     # }}}
5478     # check output
5479     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/0")
5480     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/1")
5481     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/2")
5482     (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")
5483     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/4")
5484     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/5")
5485     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/6")
5486     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/7")
5487     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/8")
5488     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/9")
5489     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/10")
5490     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/11")
5491     (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")
5492     (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")
5493     (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")
5494     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/15")
5495     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/16")
5496     (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")
5497     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/18")
5498     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/19")
5499     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/20")
5500     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/21")
5501     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/22")
5502     (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")
5503     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/24")
5504     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/25")
5505     # . epilogue
5506     89/<- %esp 5/r32/ebp
5507     5d/pop-to-ebp
5508     c3/return
5510 test-convert-function-with-unconditional-break-and-local-vars:
5511     # . prologue
5512     55/push-ebp
5513     89/<- %ebp 4/r32/esp
5514     # setup
5515     (clear-stream _test-input-stream)
5516     (clear-stream $_test-input-buffered-file->buffer)
5517     (clear-stream _test-output-stream)
5518     (clear-stream $_test-output-buffered-file->buffer)
5519     #
5520     (write _test-input-stream "fn foo {\n")
5521     (write _test-input-stream "  {\n")
5522     (write _test-input-stream "    var x: int\n")
5523     (write _test-input-stream "    {\n")
5524     (write _test-input-stream "      var y: int\n")
5525     (write _test-input-stream "      break\n")
5526     (write _test-input-stream "      increment x\n")
5527     (write _test-input-stream "    }\n")
5528     (write _test-input-stream "  }\n")
5529     (write _test-input-stream "}\n")
5530     # convert
5531     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
5532     (flush _test-output-buffered-file)
5533 #?     # dump _test-output-stream {{{
5534 #?     (write 2 "^")
5535 #?     (write-stream 2 _test-output-stream)
5536 #?     (write 2 "$\n")
5537 #?     (rewind-stream _test-output-stream)
5538 #?     # }}}
5539     # check output
5540     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-break-and-local-vars/0")
5541     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-break-and-local-vars/1")
5542     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-break-and-local-vars/2")
5543     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-break-and-local-vars/3")
5544     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-break-and-local-vars/4")
5545     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/5")
5546     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-break-and-local-vars/6")
5547     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/7")
5548     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-break-and-local-vars/8")
5549     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-unconditional-break-and-local-vars/9")
5550     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/10")
5551     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/11")
5552     (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")
5553     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-unconditional-break-and-local-vars/13")
5554     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/14")
5555     (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")
5556     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-break-and-local-vars/16")
5557     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/17")
5558     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-break-and-local-vars/18")
5559     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/19")
5560     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-break-and-local-vars/20")
5561     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-break-and-local-vars/21")
5562     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-break-and-local-vars/22")
5563     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-break-and-local-vars/23")
5564     # . epilogue
5565     89/<- %esp 5/r32/ebp
5566     5d/pop-to-ebp
5567     c3/return
5569 test-convert-function-with-nonlocal-unconditional-loop-and-local-vars:
5570     # . prologue
5571     55/push-ebp
5572     89/<- %ebp 4/r32/esp
5573     # setup
5574     (clear-stream _test-input-stream)
5575     (clear-stream $_test-input-buffered-file->buffer)
5576     (clear-stream _test-output-stream)
5577     (clear-stream $_test-output-buffered-file->buffer)
5578     #
5579     (write _test-input-stream "fn foo {\n")
5580     (write _test-input-stream "  a: {\n")
5581     (write _test-input-stream "    var x: int\n")
5582     (write _test-input-stream "    {\n")
5583     (write _test-input-stream "      var y: int\n")
5584     (write _test-input-stream "      loop a\n")
5585     (write _test-input-stream "      increment x\n")
5586     (write _test-input-stream "    }\n")
5587     (write _test-input-stream "  }\n")
5588     (write _test-input-stream "}\n")
5589     # convert
5590     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
5591     (flush _test-output-buffered-file)
5592 #?     # dump _test-output-stream {{{
5593 #?     (write 2 "^")
5594 #?     (write-stream 2 _test-output-stream)
5595 #?     (write 2 "$\n")
5596 #?     (rewind-stream _test-output-stream)
5597 #?     # }}}
5598     # check output
5599     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/0")
5600     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/1")
5601     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/2")
5602     (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")
5603     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/4")
5604     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/5")
5605     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/6")
5606     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/7")
5607     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/8")
5608     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/9")
5609     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/10")
5610     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/11")
5611     (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")
5612     (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")
5613     (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")
5614     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/15")
5615     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/16")
5616     (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")
5617     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/18")
5618     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/19")
5619     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/20")
5620     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/21")
5621     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/22")
5622     (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")
5623     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/24")
5624     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/25")
5625     # . epilogue
5626     89/<- %esp 5/r32/ebp
5627     5d/pop-to-ebp
5628     c3/return
5630 test-convert-function-with-local-array-var-in-mem:
5631     # . prologue
5632     55/push-ebp
5633     89/<- %ebp 4/r32/esp
5634     # setup
5635     (clear-stream _test-input-stream)
5636     (clear-stream $_test-input-buffered-file->buffer)
5637     (clear-stream _test-output-stream)
5638     (clear-stream $_test-output-buffered-file->buffer)
5639     #
5640     (write _test-input-stream "fn foo {\n")
5641     (write _test-input-stream "  var x: (array int 3)\n")
5642     (write _test-input-stream "}\n")
5643     # convert
5644     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
5645     (flush _test-output-buffered-file)
5646 #?     # dump _test-output-stream {{{
5647 #?     (write 2 "^")
5648 #?     (write-stream 2 _test-output-stream)
5649 #?     (write 2 "$\n")
5650 #?     (rewind-stream _test-output-stream)
5651 #?     # }}}
5652     # check output
5653     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-array-var-in-mem/0")
5654     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-array-var-in-mem/1")
5655     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-array-var-in-mem/2")
5656     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-array-var-in-mem/3")
5657     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-array-var-in-mem/4")
5658     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-array-var-in-mem/5")
5659     # define x
5660     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-function-with-local-array-var-in-mem/7")
5661     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-function-with-local-array-var-in-mem/8")
5662     # reclaim x
5663     (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")
5664     #
5665     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-array-var-in-mem/10")
5666     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-array-var-in-mem/11")
5667     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-array-var-in-mem/12")
5668     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-array-var-in-mem/13")
5669     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-array-var-in-mem/14")
5670     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-array-var-in-mem/15")
5671     # . epilogue
5672     89/<- %esp 5/r32/ebp
5673     5d/pop-to-ebp
5674     c3/return
5676 test-array-size-in-hex:
5677     # . prologue
5678     55/push-ebp
5679     89/<- %ebp 4/r32/esp
5680     # setup
5681     (clear-stream _test-input-stream)
5682     (clear-stream $_test-input-buffered-file->buffer)
5683     (clear-stream _test-output-stream)
5684     (clear-stream $_test-output-buffered-file->buffer)
5685     (clear-stream _test-error-stream)
5686     (clear-stream $_test-error-buffered-file->buffer)
5687     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
5688     68/push 0/imm32
5689     68/push 0/imm32
5690     89/<- %edx 4/r32/esp
5691     (tailor-exit-descriptor %edx 0x10)
5692     #
5693     (write _test-input-stream "fn foo {\n")
5694     (write _test-input-stream "  var x: (array int 10)\n")
5695     (write _test-input-stream "}\n")
5696     # convert
5697     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
5698     # registers except esp clobbered at this point
5699     # restore ed
5700     89/<- %edx 4/r32/esp
5701     (flush _test-output-buffered-file)
5702     (flush _test-error-buffered-file)
5703 #?     # dump _test-error-stream {{{
5704 #?     (write 2 "^")
5705 #?     (write-stream 2 _test-error-stream)
5706 #?     (write 2 "$\n")
5707 #?     (rewind-stream _test-error-stream)
5708 #?     # }}}
5709     # check output
5710     (check-stream-equal _test-output-stream  ""  "F - test-array-size-in-hex: output should be empty")
5711     (check-next-stream-line-equal _test-error-stream  "literal integers are always hex in Mu; start '10' with a '0x' to be unambiguous, converting it to hexadecimal as necessary."  "F - test-array-size-in-hex: error message")
5712     # check that stop(1) was called
5713     (check-ints-equal *(edx+4) 2 "F - test-array-size-in-hex: exit status")
5714     # don't restore from ebp
5715     81 0/subop/add %esp 8/imm32
5716     # . epilogue
5717     5d/pop-to-ebp
5718     c3/return
5720 test-array-size-with-metadata:
5721     # . prologue
5722     55/push-ebp
5723     89/<- %ebp 4/r32/esp
5724     # setup
5725     (clear-stream _test-input-stream)
5726     (clear-stream $_test-input-buffered-file->buffer)
5727     (clear-stream _test-output-stream)
5728     (clear-stream $_test-output-buffered-file->buffer)
5729     #
5730     (write _test-input-stream "fn foo {\n")
5731     (write _test-input-stream "  var x: (array int 3/bar)\n")
5732     (write _test-input-stream "}\n")
5733     # convert
5734     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
5735     (flush _test-output-buffered-file)
5736 #?     # dump _test-output-stream {{{
5737 #?     (write 2 "^")
5738 #?     (write-stream 2 _test-output-stream)
5739 #?     (write 2 "$\n")
5740 #?     (rewind-stream _test-output-stream)
5741 #?     # }}}
5742     # no errors
5743     # . epilogue
5744     89/<- %esp 5/r32/ebp
5745     5d/pop-to-ebp
5746     c3/return
5748 test-convert-function-with-populate:
5749     # . prologue
5750     55/push-ebp
5751     89/<- %ebp 4/r32/esp
5752     # setup
5753     (clear-stream _test-input-stream)
5754     (clear-stream $_test-input-buffered-file->buffer)
5755     (clear-stream _test-output-stream)
5756     (clear-stream $_test-output-buffered-file->buffer)
5757     #
5758     (write _test-input-stream "fn foo {\n")
5759     (write _test-input-stream "  var x/ecx: (addr handle array int) <- copy 0\n")
5760     (write _test-input-stream "  populate x, 7\n")
5761     (write _test-input-stream "}\n")
5762     # convert
5763     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
5764     (flush _test-output-buffered-file)
5765 #?     # dump _test-output-stream {{{
5766 #?     (write 2 "^")
5767 #?     (write-stream 2 _test-output-stream)
5768 #?     (write 2 "$\n")
5769 #?     (rewind-stream _test-output-stream)
5770 #?     # }}}
5771     # check output
5772     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-populate/0")
5773     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-populate/1")
5774     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-populate/2")
5775     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-populate/3")
5776     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-populate/4")
5777     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-populate/5")
5778     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-populate/6")
5779     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-populate/7")
5780     (check-next-stream-line-equal _test-output-stream "    (allocate-array2 Heap 0x00000004 7 %ecx)"  "F - test-convert-function-with-populate/8")  # 4 = size-of(int)
5781     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-populate/9")
5782     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-populate/10")
5783     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-populate/11")
5784     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-populate/12")
5785     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-populate/13")
5786     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-populate/14")
5787     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-populate/15")
5788     # . epilogue
5789     89/<- %esp 5/r32/ebp
5790     5d/pop-to-ebp
5791     c3/return
5793 # special-case for size(byte) when allocating array
5794 test-convert-function-with-local-array-of-bytes-in-mem:
5795     # . prologue
5796     55/push-ebp
5797     89/<- %ebp 4/r32/esp
5798     # setup
5799     (clear-stream _test-input-stream)
5800     (clear-stream $_test-input-buffered-file->buffer)
5801     (clear-stream _test-output-stream)
5802     (clear-stream $_test-output-buffered-file->buffer)
5803     #
5804     (write _test-input-stream "fn foo {\n")
5805     (write _test-input-stream "  var x: (array byte 3)\n")
5806     (write _test-input-stream "}\n")
5807     # convert
5808     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
5809     (flush _test-output-buffered-file)
5810 #?     # dump _test-output-stream {{{
5811 #?     (write 2 "^")
5812 #?     (write-stream 2 _test-output-stream)
5813 #?     (write 2 "$\n")
5814 #?     (rewind-stream _test-output-stream)
5815 #?     # }}}
5816     # check output
5817     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-array-of-bytes-in-mem/0")
5818     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-array-of-bytes-in-mem/1")
5819     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-array-of-bytes-in-mem/2")
5820     (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")
5821     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-array-of-bytes-in-mem/4")
5822     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-array-of-bytes-in-mem/5")
5823     # define x
5824     (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")
5825     (check-next-stream-line-equal _test-output-stream "    68/push 0x00000003/imm32"  "F - test-convert-function-with-local-array-of-bytes-in-mem/8")
5826     # reclaim x
5827     (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")
5828     #
5829     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-array-of-bytes-in-mem/10")
5830     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-array-of-bytes-in-mem/11")
5831     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-array-of-bytes-in-mem/12")
5832     (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")
5833     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-array-of-bytes-in-mem/14")
5834     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-array-of-bytes-in-mem/15")
5835     # . epilogue
5836     89/<- %esp 5/r32/ebp
5837     5d/pop-to-ebp
5838     c3/return
5840 test-convert-address:
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 "fn foo {\n")
5851     (write _test-input-stream "  var a: int\n")
5852     (write _test-input-stream "  var b/eax: (addr int) <- address a\n")
5853     (write _test-input-stream "}\n")
5854     # convert
5855     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
5856     (flush _test-output-buffered-file)
5857 #?     # dump _test-output-stream {{{
5858 #?     (write 2 "^")
5859 #?     (write-stream 2 _test-output-stream)
5860 #?     (write 2 "$\n")
5861 #?     (rewind-stream _test-output-stream)
5862 #?     # }}}
5863     # check output
5864     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-address/0")
5865     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-address/1")
5866     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-address/2")
5867     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-address/3")
5868     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-address/4")
5869     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-address/5")
5870     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-address/6")
5871     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-address/7")
5872     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000000/r32"  "F - test-convert-address/8")
5873     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-address/9")
5874     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-address/10")
5875     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-address/11")
5876     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-address/12")
5877     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-address/13")
5878     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-address/14")
5879     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-address/15")
5880     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-address/16")
5881     # . epilogue
5882     89/<- %esp 5/r32/ebp
5883     5d/pop-to-ebp
5884     c3/return
5886 test-convert-floating-point-convert:
5887     # . prologue
5888     55/push-ebp
5889     89/<- %ebp 4/r32/esp
5890     # setup
5891     (clear-stream _test-input-stream)
5892     (clear-stream $_test-input-buffered-file->buffer)
5893     (clear-stream _test-output-stream)
5894     (clear-stream $_test-output-buffered-file->buffer)
5895     #
5896     (write _test-input-stream "fn foo {\n")
5897     (write _test-input-stream "  var a/eax: int <- copy 0\n")
5898     (write _test-input-stream "  var b/xmm1: float <- convert a\n")
5899     (write _test-input-stream "}\n")
5900     # convert
5901     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
5902     (flush _test-output-buffered-file)
5903 #?     # dump _test-output-stream {{{
5904 #?     (write 2 "^")
5905 #?     (write-stream 2 _test-output-stream)
5906 #?     (write 2 "$\n")
5907 #?     (rewind-stream _test-output-stream)
5908 #?     # }}}
5909     # check output
5910     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-floating-point-convert/0")
5911     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-floating-point-convert/1")
5912     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-floating-point-convert/2")
5913     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-floating-point-convert/3")
5914     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-floating-point-convert/4")
5915     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-floating-point-convert/5")
5916     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-floating-point-convert/6")
5917     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"  "F - test-convert-floating-point-convert/7")
5918     (check-next-stream-line-equal _test-output-stream "    81 5/subop/subtract %esp 4/imm32"  "F - test-convert-floating-point-convert/8")
5919     (check-next-stream-line-equal _test-output-stream "    f3 0f 11/<- *esp 1/x32"  "F - test-convert-floating-point-convert/9")
5920     (check-next-stream-line-equal _test-output-stream "    f3 0f 2a/convert-to-float %eax 0x00000001/x32"  "F - test-convert-floating-point-convert/10")
5921     (check-next-stream-line-equal _test-output-stream "    f3 0f 10/-> *esp 1/x32"  "F - test-convert-floating-point-convert/11")
5922     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 4/imm32"  "F - test-floating-point-convert/12")
5923     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-convert-floating-point-convert/13")
5924     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-floating-point-convert/14")
5925     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-floating-point-convert/15")
5926     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-floating-point-convert/16")
5927     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-floating-point-convert/17")
5928     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-floating-point-convert/18")
5929     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-floating-point-convert/19")
5930     # . epilogue
5931     89/<- %esp 5/r32/ebp
5932     5d/pop-to-ebp
5933     c3/return
5935 test-convert-floating-point-convert-2:
5936     # . prologue
5937     55/push-ebp
5938     89/<- %ebp 4/r32/esp
5939     # setup
5940     (clear-stream _test-input-stream)
5941     (clear-stream $_test-input-buffered-file->buffer)
5942     (clear-stream _test-output-stream)
5943     (clear-stream $_test-output-buffered-file->buffer)
5944     #
5945     (write _test-input-stream "fn foo {\n")
5946     (write _test-input-stream "  var a/eax: int <- copy 0\n")
5947     (write _test-input-stream "  var b/xmm1: float <- convert a\n")
5948     (write _test-input-stream "  a <- convert b\n")
5949     (write _test-input-stream "}\n")
5950     # convert
5951     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
5952     (flush _test-output-buffered-file)
5953 #?     # dump _test-output-stream {{{
5954 #?     (write 2 "^")
5955 #?     (write-stream 2 _test-output-stream)
5956 #?     (write 2 "$\n")
5957 #?     (rewind-stream _test-output-stream)
5958 #?     # }}}
5959     # check output
5960     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-floating-point-convert-2/0")
5961     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-floating-point-convert-2/1")
5962     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-floating-point-convert-2/2")
5963     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-floating-point-convert-2/3")
5964     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-floating-point-convert-2/4")
5965     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-floating-point-convert-2/5")
5966     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-floating-point-convert-2/6")
5967     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"  "F - test-convert-floating-point-convert-2/7")
5968     (check-next-stream-line-equal _test-output-stream "    81 5/subop/subtract %esp 4/imm32"  "F - test-convert-floating-point-convert-2/8")
5969     (check-next-stream-line-equal _test-output-stream "    f3 0f 11/<- *esp 1/x32"  "F - test-convert-floating-point-convert-2/9")
5970     (check-next-stream-line-equal _test-output-stream "    f3 0f 2a/convert-to-float %eax 0x00000001/x32"  "F - test-convert-floating-point-convert-2/10")
5971     (check-next-stream-line-equal _test-output-stream "    f3 0f 2d/convert-to-int %xmm1 0x00000000/r32"  "F - test-convert-floating-point-convert-2/11")
5972     (check-next-stream-line-equal _test-output-stream "    f3 0f 10/-> *esp 1/x32"  "F - test-convert-floating-point-convert-2/12")
5973     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 4/imm32"  "F - test-floating-point-convert-2/13")
5974     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-convert-floating-point-convert-2/14")
5975     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-floating-point-convert-2/15")
5976     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-floating-point-convert-2/16")
5977     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-floating-point-convert-2/17")
5978     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-floating-point-convert-2/18")
5979     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-floating-point-convert-2/19")
5980     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-floating-point-convert-2/20")
5981     # . epilogue
5982     89/<- %esp 5/r32/ebp
5983     5d/pop-to-ebp
5984     c3/return
5986 test-convert-floating-point-operation:
5987     # . prologue
5988     55/push-ebp
5989     89/<- %ebp 4/r32/esp
5990     # setup
5991     (clear-stream _test-input-stream)
5992     (clear-stream $_test-input-buffered-file->buffer)
5993     (clear-stream _test-output-stream)
5994     (clear-stream $_test-output-buffered-file->buffer)
5995     #
5996     (write _test-input-stream "fn f {\n")
5997     (write _test-input-stream "  var m: float\n")
5998     (write _test-input-stream "  var x/xmm1: float <- copy m\n")
5999     (write _test-input-stream "  var y/xmm5: float <- copy m\n")
6000     (write _test-input-stream "  x <- copy y\n")
6001     (write _test-input-stream "  copy-to m, y\n")
6002     (write _test-input-stream "  x <- add y\n")
6003     (write _test-input-stream "  x <- add m\n")
6004     (write _test-input-stream "  x <- subtract y\n")
6005     (write _test-input-stream "  x <- subtract m\n")
6006     (write _test-input-stream "  x <- multiply y\n")
6007     (write _test-input-stream "  x <- multiply m\n")
6008     (write _test-input-stream "  x <- divide y\n")
6009     (write _test-input-stream "  x <- divide m\n")
6010     (write _test-input-stream "  x <- reciprocal y\n")
6011     (write _test-input-stream "  x <- reciprocal m\n")
6012     (write _test-input-stream "  x <- square-root y\n")
6013     (write _test-input-stream "  x <- square-root m\n")
6014     (write _test-input-stream "  x <- inverse-square-root y\n")
6015     (write _test-input-stream "  x <- inverse-square-root m\n")
6016     (write _test-input-stream "  x <- max y\n")
6017     (write _test-input-stream "  x <- max m\n")
6018     (write _test-input-stream "  x <- min y\n")
6019     (write _test-input-stream "  x <- min m\n")
6020     (write _test-input-stream "  compare x, y\n")
6021     (write _test-input-stream "  compare x, m\n")
6022     (write _test-input-stream "}\n")
6023     # convert
6024     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
6025     (flush _test-output-buffered-file)
6026 #?     # dump _test-output-stream {{{
6027 #?     (write 2 "^")
6028 #?     (write-stream 2 _test-output-stream)
6029 #?     (write 2 "$\n")
6030 #?     (rewind-stream _test-output-stream)
6031 #?     # }}}
6032     # check output
6033     (check-next-stream-line-equal _test-output-stream "f:"                                                                     "F - test-convert-floating-point-operation/0")
6034     (check-next-stream-line-equal _test-output-stream "  # . prologue"                                                         "F - test-convert-floating-point-operation/1")
6035     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                                                          "F - test-convert-floating-point-operation/2")
6036     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                                                 "F - test-convert-floating-point-operation/3")
6037     (check-next-stream-line-equal _test-output-stream "  {"                                                                    "F - test-convert-floating-point-operation/4")
6038     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"                                                    "F - test-convert-floating-point-operation/5")
6039     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"                                                    "F - test-convert-floating-point-operation/6")
6040     (check-next-stream-line-equal _test-output-stream "    81 5/subop/subtract %esp 4/imm32"                                   "F - test-convert-floating-point-operation/7")
6041     (check-next-stream-line-equal _test-output-stream "    f3 0f 11/<- *esp 1/x32"                                             "F - test-convert-floating-point-operation/8")
6042     (check-next-stream-line-equal _test-output-stream "    f3 0f 10/copy *(ebp+0xfffffffc) 0x00000001/x32"                     "F - test-convert-floating-point-operation/9")
6043     (check-next-stream-line-equal _test-output-stream "    81 5/subop/subtract %esp 4/imm32"                                   "F - test-convert-floating-point-operation/10")
6044     (check-next-stream-line-equal _test-output-stream "    f3 0f 11/<- *esp 5/x32"                                             "F - test-convert-floating-point-operation/11")
6045     (check-next-stream-line-equal _test-output-stream "    f3 0f 10/copy *(ebp+0xfffffffc) 0x00000005/x32"                     "F - test-convert-floating-point-operation/12")
6046     (check-next-stream-line-equal _test-output-stream "    f3 0f 11/copy %xmm1 0x00000005/x32"                                 "F - test-convert-floating-point-operation/13")
6047     (check-next-stream-line-equal _test-output-stream "    f3 0f 11/copy *(ebp+0xfffffffc) 0x00000005/x32"                     "F - test-convert-floating-point-operation/14")
6048     (check-next-stream-line-equal _test-output-stream "    f3 0f 58/add %xmm5 0x00000001/x32"                                  "F - test-convert-floating-point-operation/15")
6049     (check-next-stream-line-equal _test-output-stream "    f3 0f 58/add *(ebp+0xfffffffc) 0x00000001/x32"                      "F - test-convert-floating-point-operation/16")
6050     (check-next-stream-line-equal _test-output-stream "    f3 0f 5c/subtract %xmm5 0x00000001/x32"                             "F - test-convert-floating-point-operation/17")
6051     (check-next-stream-line-equal _test-output-stream "    f3 0f 5c/subtract *(ebp+0xfffffffc) 0x00000001/x32"                 "F - test-convert-floating-point-operation/18")
6052     (check-next-stream-line-equal _test-output-stream "    f3 0f 59/multiply %xmm5 0x00000001/x32"                             "F - test-convert-floating-point-operation/19")
6053     (check-next-stream-line-equal _test-output-stream "    f3 0f 59/multiply *(ebp+0xfffffffc) 0x00000001/x32"                 "F - test-convert-floating-point-operation/20")
6054     (check-next-stream-line-equal _test-output-stream "    f3 0f 5e/divide %xmm5 0x00000001/x32"                               "F - test-convert-floating-point-operation/21")
6055     (check-next-stream-line-equal _test-output-stream "    f3 0f 5e/divide *(ebp+0xfffffffc) 0x00000001/x32"                   "F - test-convert-floating-point-operation/22")
6056     (check-next-stream-line-equal _test-output-stream "    f3 0f 53/reciprocal %xmm5 0x00000001/x32"                           "F - test-convert-floating-point-operation/23")
6057     (check-next-stream-line-equal _test-output-stream "    f3 0f 53/reciprocal *(ebp+0xfffffffc) 0x00000001/x32"               "F - test-convert-floating-point-operation/24")
6058     (check-next-stream-line-equal _test-output-stream "    f3 0f 51/square-root %xmm5 0x00000001/x32"                          "F - test-convert-floating-point-operation/25")
6059     (check-next-stream-line-equal _test-output-stream "    f3 0f 51/square-root *(ebp+0xfffffffc) 0x00000001/x32"              "F - test-convert-floating-point-operation/26")
6060     (check-next-stream-line-equal _test-output-stream "    f3 0f 52/inverse-square-root %xmm5 0x00000001/x32"                  "F - test-convert-floating-point-operation/27")
6061     (check-next-stream-line-equal _test-output-stream "    f3 0f 52/inverse-square-root *(ebp+0xfffffffc) 0x00000001/x32"      "F - test-convert-floating-point-operation/28")
6062     (check-next-stream-line-equal _test-output-stream "    f3 0f 5f/max %xmm5 0x00000001/x32"                                  "F - test-convert-floating-point-operation/29")
6063     (check-next-stream-line-equal _test-output-stream "    f3 0f 5f/max *(ebp+0xfffffffc) 0x00000001/x32"                      "F - test-convert-floating-point-operation/30")
6064     (check-next-stream-line-equal _test-output-stream "    f3 0f 5d/min %xmm5 0x00000001/x32"                                  "F - test-convert-floating-point-operation/31")
6065     (check-next-stream-line-equal _test-output-stream "    f3 0f 5d/min *(ebp+0xfffffffc) 0x00000001/x32"                      "F - test-convert-floating-point-operation/32")
6066     (check-next-stream-line-equal _test-output-stream "    0f 2f/compare %xmm5 0x00000001/x32"                                 "F - test-convert-floating-point-operation/33")
6067     (check-next-stream-line-equal _test-output-stream "    0f 2f/compare *(ebp+0xfffffffc) 0x00000001/x32"                     "F - test-convert-floating-point-operation/34")
6068     (check-next-stream-line-equal _test-output-stream "    f3 0f 10/-> *esp 5/x32"                                             "F - test-convert-floating-point-operation/35")
6069     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 4/imm32"                                        "F - test-convert-floating-point-operation/36")
6070     (check-next-stream-line-equal _test-output-stream "    f3 0f 10/-> *esp 1/x32"                                             "F - test-convert-floating-point-operation/37")
6071     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 4/imm32"                                        "F - test-convert-floating-point-operation/38")
6072     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"                               "F - test-convert-floating-point-operation/39")
6073     (check-next-stream-line-equal _test-output-stream "  }"                                                                    "F - test-convert-floating-point-operation/40")
6074     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"                                                   "F - test-convert-floating-point-operation/41")
6075     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                                                         "F - test-convert-floating-point-operation/42")
6076     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                                                 "F - test-convert-floating-point-operation/43")
6077     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                                                        "F - test-convert-floating-point-operation/44")
6078     (check-next-stream-line-equal _test-output-stream "  c3/return"                                                            "F - test-convert-floating-point-operation/45")
6079     # . epilogue
6080     89/<- %esp 5/r32/ebp
6081     5d/pop-to-ebp
6082     c3/return
6084 test-convert-floating-point-dereferenced:
6085     # . prologue
6086     55/push-ebp
6087     89/<- %ebp 4/r32/esp
6088     # setup
6089     (clear-stream _test-input-stream)
6090     (clear-stream $_test-input-buffered-file->buffer)
6091     (clear-stream _test-output-stream)
6092     (clear-stream $_test-output-buffered-file->buffer)
6093     #
6094     (write _test-input-stream "fn f {\n")
6095     (write _test-input-stream "  var m: float\n")
6096     (write _test-input-stream "  var x/xmm1: float <- copy m\n")
6097     (write _test-input-stream "  var y/eax: (addr float) <- copy 0\n")
6098     (write _test-input-stream "  x <- multiply *y\n")
6099     (write _test-input-stream "}\n")
6100     # convert
6101     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
6102     (flush _test-output-buffered-file)
6103 #?     # dump _test-output-stream {{{
6104 #?     (write 2 "^")
6105 #?     (write-stream 2 _test-output-stream)
6106 #?     (write 2 "$\n")
6107 #?     (rewind-stream _test-output-stream)
6108 #?     # }}}
6109     # check output
6110     (check-next-stream-line-equal _test-output-stream "f:"                                                                     "F - test-convert-floating-point-dereferenced/0")
6111     (check-next-stream-line-equal _test-output-stream "  # . prologue"                                                         "F - test-convert-floating-point-dereferenced/1")
6112     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                                                          "F - test-convert-floating-point-dereferenced/2")
6113     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                                                 "F - test-convert-floating-point-dereferenced/3")
6114     (check-next-stream-line-equal _test-output-stream "  {"                                                                    "F - test-convert-floating-point-dereferenced/4")
6115     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"                                                    "F - test-convert-floating-point-dereferenced/5")
6116     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"                                                    "F - test-convert-floating-point-dereferenced/6")
6117     (check-next-stream-line-equal _test-output-stream "    81 5/subop/subtract %esp 4/imm32"                                   "F - test-convert-floating-point-dereferenced/7")
6118     (check-next-stream-line-equal _test-output-stream "    f3 0f 11/<- *esp 1/x32"                                             "F - test-convert-floating-point-dereferenced/8")
6119     (check-next-stream-line-equal _test-output-stream "    f3 0f 10/copy *(ebp+0xfffffffc) 0x00000001/x32"                     "F - test-convert-floating-point-dereferenced/9")
6120     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                                               "F - test-convert-floating-point-dereferenced/10")
6121     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                                             "F - test-convert-floating-point-dereferenced/11")
6122     (check-next-stream-line-equal _test-output-stream "    f3 0f 59/multiply *eax 0x00000001/x32"                              "F - test-convert-floating-point-dereferenced/12")
6123     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                                                "F - test-convert-floating-point-dereferenced/13")
6124     (check-next-stream-line-equal _test-output-stream "    f3 0f 10/-> *esp 1/x32"                                             "F - test-convert-floating-point-dereferenced/14")
6125     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 4/imm32"                                        "F - test-convert-floating-point-dereferenced/15")
6126     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"                               "F - test-convert-floating-point-dereferenced/16")
6127     (check-next-stream-line-equal _test-output-stream "  }"                                                                    "F - test-convert-floating-point-dereferenced/17")
6128     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"                                                   "F - test-convert-floating-point-dereferenced/18")
6129     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                                                         "F - test-convert-floating-point-dereferenced/19")
6130     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                                                 "F - test-convert-floating-point-dereferenced/20")
6131     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                                                        "F - test-convert-floating-point-dereferenced/21")
6132     (check-next-stream-line-equal _test-output-stream "  c3/return"                                                            "F - test-convert-floating-point-dereferenced/22")
6133     # . epilogue
6134     89/<- %esp 5/r32/ebp
6135     5d/pop-to-ebp
6136     c3/return
6138 test-convert-length-of-array:
6139     # . prologue
6140     55/push-ebp
6141     89/<- %ebp 4/r32/esp
6142     # setup
6143     (clear-stream _test-input-stream)
6144     (clear-stream $_test-input-buffered-file->buffer)
6145     (clear-stream _test-output-stream)
6146     (clear-stream $_test-output-buffered-file->buffer)
6147     #
6148     (write _test-input-stream "fn foo a: (addr array int) {\n")
6149     (write _test-input-stream "  var b/eax: (addr array int) <- copy a\n")
6150     (write _test-input-stream "  var c/eax: int <- length b\n")
6151     (write _test-input-stream "}\n")
6152     # convert
6153     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
6154     (flush _test-output-buffered-file)
6155 #?     # dump _test-output-stream {{{
6156 #?     (write 2 "^")
6157 #?     (write-stream 2 _test-output-stream)
6158 #?     (write 2 "$\n")
6159 #?     (rewind-stream _test-output-stream)
6160 #?     # }}}
6161     # check output
6162     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array/0")
6163     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array/1")
6164     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array/2")
6165     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array/3")
6166     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array/4")
6167     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array/5")
6168     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array/6")
6169     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-length-of-array/7")
6170     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array/8")
6171     (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array/9")
6172     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array/10")
6173     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array/11")
6174     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array/12")
6175     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array/13")
6176     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array/14")
6177     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array/15")
6178     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array/16")
6179     # . epilogue
6180     89/<- %esp 5/r32/ebp
6181     5d/pop-to-ebp
6182     c3/return
6184 # special-case for size(byte) when computing array length
6185 test-convert-length-of-array-of-bytes:
6186     # . prologue
6187     55/push-ebp
6188     89/<- %ebp 4/r32/esp
6189     # setup
6190     (clear-stream _test-input-stream)
6191     (clear-stream $_test-input-buffered-file->buffer)
6192     (clear-stream _test-output-stream)
6193     (clear-stream $_test-output-buffered-file->buffer)
6194     #
6195     (write _test-input-stream "fn foo a: (addr array byte) {\n")
6196     (write _test-input-stream "  var b/eax: (addr array byte) <- copy a\n")
6197     (write _test-input-stream "  var c/eax: int <- length b\n")
6198     (write _test-input-stream "}\n")
6199     # convert
6200     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
6201     (flush _test-output-buffered-file)
6202 #?     # dump _test-output-stream {{{
6203 #?     (write 2 "^")
6204 #?     (write-stream 2 _test-output-stream)
6205 #?     (write 2 "$\n")
6206 #?     (rewind-stream _test-output-stream)
6207 #?     # }}}
6208     # check output
6209     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-bytes/0")
6210     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-bytes/1")
6211     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-bytes/2")
6212     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-bytes/3")
6213     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-bytes/4")
6214     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-bytes/5")
6215     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-bytes/6")
6216     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-length-of-array-of-bytes/7")
6217     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-bytes/8")
6218     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-bytes/9")
6219     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-bytes/10")
6220     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-bytes/11")
6221     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-bytes/12")
6222     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-bytes/13")
6223     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-bytes/14")
6224     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-bytes/15")
6225     # . epilogue
6226     89/<- %esp 5/r32/ebp
6227     5d/pop-to-ebp
6228     c3/return
6230 test-convert-length-of-array-on-stack:
6231     # . prologue
6232     55/push-ebp
6233     89/<- %ebp 4/r32/esp
6234     # setup
6235     (clear-stream _test-input-stream)
6236     (clear-stream $_test-input-buffered-file->buffer)
6237     (clear-stream _test-output-stream)
6238     (clear-stream $_test-output-buffered-file->buffer)
6239     #
6240     (write _test-input-stream "fn foo {\n")
6241     (write _test-input-stream "  var a: (array int 3)\n")
6242     (write _test-input-stream "  var b/eax: int <- length a\n")
6243     (write _test-input-stream "}\n")
6244     # convert
6245     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
6246     (flush _test-output-buffered-file)
6247 #?     # dump _test-output-stream {{{
6248 #?     (write 2 "^")
6249 #?     (write-stream 2 _test-output-stream)
6250 #?     (write 2 "$\n")
6251 #?     (rewind-stream _test-output-stream)
6252 #?     # }}}
6253     # check output
6254     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-on-stack/0")
6255     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-on-stack/1")
6256     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-on-stack/2")
6257     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-on-stack/3")
6258     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-on-stack/4")
6259     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-on-stack/5")
6260     # define x
6261     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-length-of-array-on-stack/6")
6262     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-length-of-array-on-stack/7")
6263     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-on-stack/8")
6264     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0xfffffff0) 0x00000000/r32"  "F - test-convert-length-of-array-on-stack/9")
6265     (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array-on-stack/10")
6266     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-on-stack/11")
6267     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"  "F - test-convert-length-of-array-on-stack/12")
6268     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-on-stack/13")
6269     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-on-stack/14")
6270     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-on-stack/15")
6271     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-on-stack/16")
6272     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-on-stack/17")
6273     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-on-stack/18")
6274     # . epilogue
6275     89/<- %esp 5/r32/ebp
6276     5d/pop-to-ebp
6277     c3/return
6279 test-reg-var-def-with-read-of-same-register:
6280     # . prologue
6281     55/push-ebp
6282     89/<- %ebp 4/r32/esp
6283     # setup
6284     (clear-stream _test-input-stream)
6285     (clear-stream $_test-input-buffered-file->buffer)
6286     (clear-stream _test-output-stream)
6287     (clear-stream $_test-output-buffered-file->buffer)
6288     (clear-stream _test-error-stream)
6289     (clear-stream $_test-error-buffered-file->buffer)
6290     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)  # bytes of args in call to convert-mu
6291     68/push 0/imm32
6292     68/push 0/imm32
6293     89/<- %edx 4/r32/esp
6294     (tailor-exit-descriptor %edx 0x10)
6295     #
6296     (write _test-input-stream "fn foo {\n")
6297     (write _test-input-stream "  var x/eax: int <- copy 3\n")
6298     (write _test-input-stream "  var y/eax: int <- add x\n")
6299     (write _test-input-stream "}\n")
6300     # convert
6301     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
6302     # registers except esp could be clobbered at this point (though they shouldn't be)
6303     # restore ed
6304     89/<- %edx 4/r32/esp
6305     (flush _test-output-buffered-file)
6306     (flush _test-error-buffered-file)
6307 #?     # dump _test-output-stream {{{
6308 #?     (write 2 "^")
6309 #?     (write-stream 2 _test-output-stream)
6310 #?     (write 2 "$\n")
6311 #?     (rewind-stream _test-output-stream)
6312 #?     # }}}
6313 #?     # dump _test-error-stream {{{
6314 #?     (write 2 "^")
6315 #?     (write-stream 2 _test-error-stream)
6316 #?     (write 2 "$\n")
6317 #?     (rewind-stream _test-error-stream)
6318 #?     # }}}
6319     (check-stream-equal _test-error-stream  ""  "F - test-reg-var-def-with-read-of-same-register: error stream should be empty")
6320     # check output
6321     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-reg-var-def-with-read-of-same-register/0")
6322     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-reg-var-def-with-read-of-same-register/1")
6323     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-reg-var-def-with-read-of-same-register/2")
6324     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-reg-var-def-with-read-of-same-register/3")
6325     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-reg-var-def-with-read-of-same-register/4")
6326     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-reg-var-def-with-read-of-same-register/5")
6327     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-reg-var-def-with-read-of-same-register/6")
6328     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"                  "F - test-reg-var-def-with-read-of-same-register/7")
6329     (check-next-stream-line-equal _test-output-stream "    01/add-to %eax 0x00000000/r32"           "F - test-reg-var-def-with-read-of-same-register/8")
6330     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-reg-var-def-with-read-of-same-register/9")
6331     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-reg-var-def-with-read-of-same-register/10")
6332     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-reg-var-def-with-read-of-same-register/11")
6333     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-reg-var-def-with-read-of-same-register/12")
6334     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-reg-var-def-with-read-of-same-register/13")
6335     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-reg-var-def-with-read-of-same-register/14")
6336     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-reg-var-def-with-read-of-same-register/15")
6337     # don't restore from ebp
6338     81 0/subop/add %esp 8/imm32
6339     # . epilogue
6340     5d/pop-to-ebp
6341     c3/return
6343 test-convert-index-into-array:
6344     # . prologue
6345     55/push-ebp
6346     89/<- %ebp 4/r32/esp
6347     # setup
6348     (clear-stream _test-input-stream)
6349     (clear-stream $_test-input-buffered-file->buffer)
6350     (clear-stream _test-output-stream)
6351     (clear-stream $_test-output-buffered-file->buffer)
6352     #
6353     (write _test-input-stream "fn foo {\n")
6354     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
6355     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
6356     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
6357     (write _test-input-stream "}\n")
6358     # convert
6359     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
6360     (flush _test-output-buffered-file)
6361 #?     # dump _test-output-stream {{{
6362 #?     (write 2 "^")
6363 #?     (write-stream 2 _test-output-stream)
6364 #?     (write 2 "$\n")
6365 #?     (rewind-stream _test-output-stream)
6366 #?     # }}}
6367     # check output
6368     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array/0")
6369     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array/1")
6370     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array/2")
6371     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array/3")
6372     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array/4")
6373     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array/5")
6374     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array/6")
6375     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array/7")
6376     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array/8")
6377     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array/9")
6378     (check-next-stream-line-equal _test-output-stream "    (__check-mu-array-bounds %ecx 0x00000004 *eax \"foo\" \"arr\")"  "F - test-convert-index-into-array/10")
6379     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %eax 0/imm32"  "F - test-convert-index-into-array/11")
6380     (check-next-stream-line-equal _test-output-stream "    0f 84/jump-if-= __mu-abort-null-index-base-address/disp32"  "F - test-convert-index-into-array/12")
6381     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx<<0x00000002 + 4) 0x00000000/r32"  "F - test-convert-index-into-array/13")
6382     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array/14")
6383     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array/15")
6384     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array/16")
6385     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array/17")
6386     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array/18")
6387     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array/19")
6388     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array/20")
6389     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array/21")
6390     # . epilogue
6391     89/<- %esp 5/r32/ebp
6392     5d/pop-to-ebp
6393     c3/return
6395 test-convert-index-into-array-of-bytes:
6396     # . prologue
6397     55/push-ebp
6398     89/<- %ebp 4/r32/esp
6399     # setup
6400     (clear-stream _test-input-stream)
6401     (clear-stream $_test-input-buffered-file->buffer)
6402     (clear-stream _test-output-stream)
6403     (clear-stream $_test-output-buffered-file->buffer)
6404     #
6405     (write _test-input-stream "fn foo {\n")
6406     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
6407     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
6408     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, idx\n")
6409     (write _test-input-stream "}\n")
6410     # convert
6411     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
6412     (flush _test-output-buffered-file)
6413 #?     # dump _test-output-stream {{{
6414 #?     (write 2 "^")
6415 #?     (write-stream 2 _test-output-stream)
6416 #?     (write 2 "$\n")
6417 #?     (rewind-stream _test-output-stream)
6418 #?     # }}}
6419     # check output
6420     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes/0")
6421     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes/1")
6422     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes/2")
6423     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes/3")
6424     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes/4")
6425     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes/5")
6426     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes/6")
6427     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-of-bytes/7")
6428     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes/8")
6429     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-of-bytes/9")
6430     (check-next-stream-line-equal _test-output-stream "    (__check-mu-array-bounds %ecx 0x00000001 *eax \"foo\" \"arr\")"  "F - test-convert-index-into-array-of-bytes/10")
6431     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %eax 0/imm32"  "F - test-convert-index-into-array-of-bytes/11")
6432     (check-next-stream-line-equal _test-output-stream "    0f 84/jump-if-= __mu-abort-null-index-base-address/disp32"  "F - test-convert-index-into-array-of-bytes/12")
6433     (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/13")
6434     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes/14")
6435     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes/15")
6436     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes/16")
6437     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes/17")
6438     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes/18")
6439     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes/19")
6440     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes/20")
6441     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes/21")
6442     # . epilogue
6443     89/<- %esp 5/r32/ebp
6444     5d/pop-to-ebp
6445     c3/return
6447 test-convert-index-into-array-with-literal:
6448     # . prologue
6449     55/push-ebp
6450     89/<- %ebp 4/r32/esp
6451     # setup
6452     (clear-stream _test-input-stream)
6453     (clear-stream $_test-input-buffered-file->buffer)
6454     (clear-stream _test-output-stream)
6455     (clear-stream $_test-output-buffered-file->buffer)
6456     #
6457     (write _test-input-stream "fn foo {\n")
6458     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
6459     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
6460     (write _test-input-stream "}\n")
6461     # convert
6462     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
6463     (flush _test-output-buffered-file)
6464 #?     # dump _test-output-stream {{{
6465 #?     (write 2 "^")
6466 #?     (write-stream 2 _test-output-stream)
6467 #?     (write 2 "$\n")
6468 #?     (rewind-stream _test-output-stream)
6469 #?     # }}}
6470     # check output
6471     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-with-literal/0")
6472     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-with-literal/1")
6473     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-with-literal/2")
6474     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-with-literal/3")
6475     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-with-literal/4")
6476     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-with-literal/5")
6477     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-with-literal/6")
6478     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-with-literal/7")
6479     (check-next-stream-line-equal _test-output-stream "    (__check-mu-array-bounds 2 0x00000004 *eax \"foo\" \"arr\")"  "F - test-convert-index-into-array-with-literal/8")
6480     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %eax 0/imm32"  "F - test-convert-index-into-array-with-literal/9")
6481     (check-next-stream-line-equal _test-output-stream "    0f 84/jump-if-= __mu-abort-null-index-base-address/disp32"  "F - test-convert-index-into-array-with-literal/10")
6482                                                                                  # 2 * 4 bytes/elem + 4 bytes for size = offset 12
6483     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x0000000c) 0x00000000/r32"  "F - test-convert-index-into-array-with-literal/11")
6484     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-with-literal/12")
6485     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-with-literal/13")
6486     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-with-literal/14")
6487     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-with-literal/15")
6488     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-with-literal/16")
6489     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-with-literal/17")
6490     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-with-literal/18")
6491     # . epilogue
6492     89/<- %esp 5/r32/ebp
6493     5d/pop-to-ebp
6494     c3/return
6496 test-convert-index-into-array-of-bytes-with-literal:
6497     # . prologue
6498     55/push-ebp
6499     89/<- %ebp 4/r32/esp
6500     # setup
6501     (clear-stream _test-input-stream)
6502     (clear-stream $_test-input-buffered-file->buffer)
6503     (clear-stream _test-output-stream)
6504     (clear-stream $_test-output-buffered-file->buffer)
6505     #
6506     (write _test-input-stream "fn foo {\n")
6507     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
6508     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, 2\n")
6509     (write _test-input-stream "}\n")
6510     # convert
6511     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
6512     (flush _test-output-buffered-file)
6513 #?     # dump _test-output-stream {{{
6514 #?     (write 2 "^")
6515 #?     (write-stream 2 _test-output-stream)
6516 #?     (write 2 "$\n")
6517 #?     (rewind-stream _test-output-stream)
6518 #?     # }}}
6519     # check output
6520     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-with-literal/0")
6521     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-with-literal/1")
6522     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-with-literal/2")
6523     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-with-literal/3")
6524     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-with-literal/4")
6525     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-with-literal/5")
6526     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-with-literal/6")
6527     (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")
6528     (check-next-stream-line-equal _test-output-stream "    (__check-mu-array-bounds 2 0x00000001 *eax \"foo\" \"arr\")"  "F - test-convert-index-into-array-of-bytes-with-literal/8")
6529     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %eax 0/imm32"  "F - test-convert-index-into-array-of-bytes-with-literal/9")
6530     (check-next-stream-line-equal _test-output-stream "    0f 84/jump-if-= __mu-abort-null-index-base-address/disp32"  "F - test-convert-index-into-array-of-bytes-with-literal/10")
6531                                                                                  # 2 * 1 byte/elem + 4 bytes for size = offset 6
6532     (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/11")
6533     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-with-literal/12")
6534     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-with-literal/13")
6535     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-with-literal/14")
6536     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-with-literal/15")
6537     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-with-literal/16")
6538     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-with-literal/17")
6539     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-with-literal/18")
6540     # . epilogue
6541     89/<- %esp 5/r32/ebp
6542     5d/pop-to-ebp
6543     c3/return
6545 test-convert-index-into-array-on-stack:
6546     # . prologue
6547     55/push-ebp
6548     89/<- %ebp 4/r32/esp
6549     # setup
6550     (clear-stream _test-input-stream)
6551     (clear-stream $_test-input-buffered-file->buffer)
6552     (clear-stream _test-output-stream)
6553     (clear-stream $_test-output-buffered-file->buffer)
6554     #
6555     (write _test-input-stream "fn foo {\n")
6556     (write _test-input-stream "  var arr: (array int 3)\n")
6557     (write _test-input-stream "  var idx/eax: int <- copy 2\n")
6558     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
6559     (write _test-input-stream "}\n")
6560     # convert
6561     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
6562     (flush _test-output-buffered-file)
6563 #?     # dump _test-output-stream {{{
6564 #?     (write 2 "^")
6565 #?     (write-stream 2 _test-output-stream)
6566 #?     (write 2 "$\n")
6567 #?     (rewind-stream _test-output-stream)
6568 #?     # }}}
6569     # check output
6570     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack/0")
6571     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack/1")
6572     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack/2")
6573     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack/3")
6574     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack/4")
6575     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack/5")
6576     # var arr
6577     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack/6")
6578     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack/7")
6579     # var idx
6580     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack/8")
6581     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 2/imm32"                  "F - test-convert-index-into-array-on-stack/9")
6582     (check-next-stream-line-equal _test-output-stream "    (__check-mu-array-bounds %eax 0x00000004 *(ebp+0xfffffff0) \"foo\" \"arr\")"  "F - test-convert-index-into-array-on-stack/10")
6583     # var x is at (ebp-0x10) + idx<<2 + 4 = ebp + idx<<2 - 0xc
6584     (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/11")
6585     # reclaim idx
6586     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack/12")
6587     # reclaim arr
6588     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"    "F - test-convert-index-into-array-on-stack/13")
6589     #
6590     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack/14")
6591     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack/15")
6592     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack/16")
6593     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack/17")
6594     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack/18")
6595     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack/19")
6596     # . epilogue
6597     89/<- %esp 5/r32/ebp
6598     5d/pop-to-ebp
6599     c3/return
6601 test-convert-index-into-array-on-stack-with-literal:
6602     # . prologue
6603     55/push-ebp
6604     89/<- %ebp 4/r32/esp
6605     # setup
6606     (clear-stream _test-input-stream)
6607     (clear-stream $_test-input-buffered-file->buffer)
6608     (clear-stream _test-output-stream)
6609     (clear-stream $_test-output-buffered-file->buffer)
6610     #
6611     (write _test-input-stream "fn foo {\n")
6612     (write _test-input-stream "  var arr: (array int 3)\n")
6613     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
6614     (write _test-input-stream "}\n")
6615     # convert
6616     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
6617     (flush _test-output-buffered-file)
6618 #?     # dump _test-output-stream {{{
6619 #?     (write 2 "^")
6620 #?     (write-stream 2 _test-output-stream)
6621 #?     (write 2 "$\n")
6622 #?     (rewind-stream _test-output-stream)
6623 #?     # }}}
6624     # check output
6625     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack-with-literal/0")
6626     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack-with-literal/1")
6627     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack-with-literal/2")
6628     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack-with-literal/3")
6629     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack-with-literal/4")
6630     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack-with-literal/5")
6631     # var arr
6632     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack-with-literal/6")
6633     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack-with-literal/7")
6634     # var x
6635     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack-with-literal/8")
6636     (check-next-stream-line-equal _test-output-stream "    (__check-mu-array-bounds 2 0x00000004 *(ebp+0xfffffff0) \"foo\" \"arr\")"  "F - test-convert-index-into-array-on-stack-with-literal/9")
6637     # x is at (ebp-0x10) + 4 + 2*4 = ebp-4
6638     (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/10")
6639     # reclaim x
6640     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack-with-literal/11")
6641     # reclaim arr
6642     (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/12")
6643     #
6644     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack-with-literal/13")
6645     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack-with-literal/14")
6646     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack-with-literal/15")
6647     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack-with-literal/16")
6648     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack-with-literal/17")
6649     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack-with-literal/18")
6650     # . epilogue
6651     89/<- %esp 5/r32/ebp
6652     5d/pop-to-ebp
6653     c3/return
6655 test-convert-index-into-array-of-bytes-on-stack-with-literal:
6656     # . prologue
6657     55/push-ebp
6658     89/<- %ebp 4/r32/esp
6659     # setup
6660     (clear-stream _test-input-stream)
6661     (clear-stream $_test-input-buffered-file->buffer)
6662     (clear-stream _test-output-stream)
6663     (clear-stream $_test-output-buffered-file->buffer)
6664     #
6665     (write _test-input-stream "fn foo {\n")
6666     (write _test-input-stream "  var arr: (array byte 3)\n")
6667     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, 2\n")
6668     (write _test-input-stream "}\n")
6669     # convert
6670     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
6671     (flush _test-output-buffered-file)
6672 #?     # dump _test-output-stream {{{
6673 #?     (write 2 "^")
6674 #?     (write-stream 2 _test-output-stream)
6675 #?     (write 2 "$\n")
6676 #?     (rewind-stream _test-output-stream)
6677 #?     # }}}
6678     # check output
6679     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/0")
6680     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/1")
6681     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/2")
6682     (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")
6683     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/4")
6684     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/5")
6685     # var arr
6686     (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")
6687     (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")
6688     # var x
6689     (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")
6690     (check-next-stream-line-equal _test-output-stream "    (__check-mu-array-bounds 2 0x00000001 *(ebp+0xfffffff9) \"foo\" \"arr\")"  "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/9")
6691     # x is at (ebp-7) + 4 + 2 = ebp-1
6692     (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/10")
6693     # reclaim x
6694     (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/11")
6695     # reclaim arr
6696     (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/12")
6697     #
6698     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/13")
6699     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/14")
6700     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/15")
6701     (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/16")
6702     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/17")
6703     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/18")
6704     # . epilogue
6705     89/<- %esp 5/r32/ebp
6706     5d/pop-to-ebp
6707     c3/return
6709 test-convert-index-into-array-using-offset:
6710     # . prologue
6711     55/push-ebp
6712     89/<- %ebp 4/r32/esp
6713     # setup
6714     (clear-stream _test-input-stream)
6715     (clear-stream $_test-input-buffered-file->buffer)
6716     (clear-stream _test-output-stream)
6717     (clear-stream $_test-output-buffered-file->buffer)
6718     #
6719     (write _test-input-stream "fn foo {\n")
6720     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
6721     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
6722     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
6723     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
6724     (write _test-input-stream "}\n")
6725     # convert
6726     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
6727     (flush _test-output-buffered-file)
6728 #?     # dump _test-output-stream {{{
6729 #?     (write 2 "^")
6730 #?     (write-stream 2 _test-output-stream)
6731 #?     (write 2 "$\n")
6732 #?     (rewind-stream _test-output-stream)
6733 #?     # }}}
6734     # check output
6735     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset/0")
6736     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset/1")
6737     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset/2")
6738     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset/3")
6739     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset/4")
6740     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset/5")
6741     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset/6")
6742     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-using-offset/7")
6743     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset/8")
6744     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-using-offset/9")
6745     (check-next-stream-line-equal _test-output-stream "    69/multiply %ecx 0x00000004/imm32 0x00000001/r32"  "F - test-convert-index-into-array-using-offset/10")
6746     (check-next-stream-line-equal _test-output-stream "    (__check-mu-array-bounds %ecx 1 *eax \"foo\" \"arr\")"  "F - test-convert-index-into-array-using-offset/11")
6747     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %eax 0/imm32"  "F - test-convert-index-into-array-using-offset/12")
6748     (check-next-stream-line-equal _test-output-stream "    0f 84/jump-if-= __mu-abort-null-index-base-address/disp32"  "F - test-convert-index-into-array-using-offset/13")
6749     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx + 4) 0x00000000/r32"  "F - test-convert-index-into-array-using-offset/15")
6750     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset/16")
6751     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset/17")
6752     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset/18")
6753     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset/19")
6754     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset/20")
6755     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset/21")
6756     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset/22")
6757     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset/23")
6758     # . epilogue
6759     89/<- %esp 5/r32/ebp
6760     5d/pop-to-ebp
6761     c3/return
6763 test-convert-compute-offset-using-literal-index:
6764     # . prologue
6765     55/push-ebp
6766     89/<- %ebp 4/r32/esp
6767     # setup
6768     (clear-stream _test-input-stream)
6769     (clear-stream $_test-input-buffered-file->buffer)
6770     (clear-stream _test-output-stream)
6771     (clear-stream $_test-output-buffered-file->buffer)
6772     #
6773     (write _test-input-stream "fn foo {\n")
6774     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
6775     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, 3\n")
6776     (write _test-input-stream "}\n")
6777     # convert
6778     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
6779     (flush _test-output-buffered-file)
6780 #?     # dump _test-output-stream {{{
6781 #?     (write 2 "^")
6782 #?     (write-stream 2 _test-output-stream)
6783 #?     (write 2 "$\n")
6784 #?     (rewind-stream _test-output-stream)
6785 #?     # }}}
6786     # check output
6787     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-compute-offset-using-literal-index/0")
6788     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-compute-offset-using-literal-index/1")
6789     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-compute-offset-using-literal-index/2")
6790     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-compute-offset-using-literal-index/3")
6791     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-compute-offset-using-literal-index/4")
6792     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-compute-offset-using-literal-index/5")
6793     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-compute-offset-using-literal-index/6")
6794     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-compute-offset-using-literal-index/7")
6795     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-compute-offset-using-literal-index/8")
6796     (check-next-stream-line-equal _test-output-stream "    c7/copy %ecx 0x0000000c/imm32"           "F - test-convert-compute-offset-using-literal-index/9")
6797     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-compute-offset-using-literal-index/10")
6798     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-compute-offset-using-literal-index/11")
6799     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-compute-offset-using-literal-index/12")
6800     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-compute-offset-using-literal-index/13")
6801     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-compute-offset-using-literal-index/14")
6802     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-compute-offset-using-literal-index/15")
6803     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-compute-offset-using-literal-index/16")
6804     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-compute-offset-using-literal-index/17")
6805     # . epilogue
6806     89/<- %esp 5/r32/ebp
6807     5d/pop-to-ebp
6808     c3/return
6810 test-convert-index-into-array-of-bytes-using-offset:
6811     # . prologue
6812     55/push-ebp
6813     89/<- %ebp 4/r32/esp
6814     # setup
6815     (clear-stream _test-input-stream)
6816     (clear-stream $_test-input-buffered-file->buffer)
6817     (clear-stream _test-output-stream)
6818     (clear-stream $_test-output-buffered-file->buffer)
6819     #
6820     (write _test-input-stream "fn foo {\n")
6821     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
6822     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
6823     (write _test-input-stream "  var off/ecx: (offset byte) <- compute-offset arr, idx\n")
6824     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, off\n")
6825     (write _test-input-stream "}\n")
6826     # convert
6827     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
6828     (flush _test-output-buffered-file)
6829 #?     # dump _test-output-stream {{{
6830 #?     (write 2 "^")
6831 #?     (write-stream 2 _test-output-stream)
6832 #?     (write 2 "$\n")
6833 #?     (rewind-stream _test-output-stream)
6834 #?     # }}}
6835     # check output
6836     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-using-offset/0")
6837     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-using-offset/1")
6838     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-using-offset/2")
6839     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-using-offset/3")
6840     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-using-offset/4")
6841     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-using-offset/5")
6842     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-using-offset/6")
6843     (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")
6844     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes-using-offset/8")
6845     (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")
6846     (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")
6847     (check-next-stream-line-equal _test-output-stream "    (__check-mu-array-bounds %ecx 1 *eax \"foo\" \"arr\")"  "F - test-convert-index-into-array-of-bytes-using-offset/11")
6848     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %eax 0/imm32"  "F - test-convert-index-into-array-of-bytes-using-offset/12")
6849     (check-next-stream-line-equal _test-output-stream "    0f 84/jump-if-= __mu-abort-null-index-base-address/disp32"  "F - test-convert-index-into-array-of-bytes-using-offset/13")
6850     (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/14")
6851     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes-using-offset/15")
6852     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-using-offset/16")
6853     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-using-offset/17")
6854     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-using-offset/18")
6855     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-using-offset/19")
6856     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-using-offset/20")
6857     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-using-offset/21")
6858     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-using-offset/22")
6859     # . epilogue
6860     89/<- %esp 5/r32/ebp
6861     5d/pop-to-ebp
6862     c3/return
6864 test-convert-index-into-array-using-offset-on-stack:
6865     # . prologue
6866     55/push-ebp
6867     89/<- %ebp 4/r32/esp
6868     # setup
6869     (clear-stream _test-input-stream)
6870     (clear-stream $_test-input-buffered-file->buffer)
6871     (clear-stream _test-output-stream)
6872     (clear-stream $_test-output-buffered-file->buffer)
6873     #
6874     (write _test-input-stream "fn foo {\n")
6875     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
6876     (write _test-input-stream "  var idx: int\n")
6877     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
6878     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
6879     (write _test-input-stream "}\n")
6880     # convert
6881     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
6882     (flush _test-output-buffered-file)
6883 #?     # dump _test-output-stream {{{
6884 #?     (write 2 "^")
6885 #?     (write-stream 2 _test-output-stream)
6886 #?     (write 2 "$\n")
6887 #?     (rewind-stream _test-output-stream)
6888 #?     # }}}
6889     # check output
6890     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset-on-stack/0")
6891     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset-on-stack/1")
6892     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset-on-stack/2")
6893     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset-on-stack/3")
6894     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset-on-stack/4")
6895     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset-on-stack/5")
6896     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset-on-stack/6")
6897     (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")
6898     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"                         "F - test-convert-index-into-array-using-offset-on-stack/8")
6899     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset-on-stack/9")
6900     (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")
6901     (check-next-stream-line-equal _test-output-stream "    (__check-mu-array-bounds %ecx 1 *eax \"foo\" \"arr\")"  "F - test-convert-index-into-array-using-offset-on-stack/11")
6902     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %eax 0/imm32"  "F - test-convert-index-into-array-using-offset-on-stack/12")
6903     (check-next-stream-line-equal _test-output-stream "    0f 84/jump-if-= __mu-abort-null-index-base-address/disp32"  "F - test-convert-index-into-array-using-offset-on-stack/13")
6904     (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/14")
6905     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset-on-stack/15")
6906     (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/16")
6907     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset-on-stack/17")
6908     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset-on-stack/18")
6909     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset-on-stack/19")
6910     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset-on-stack/20")
6911     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset-on-stack/21")
6912     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset-on-stack/22")
6913     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset-on-stack/23")
6914     # . epilogue
6915     89/<- %esp 5/r32/ebp
6916     5d/pop-to-ebp
6917     c3/return
6919 test-convert-index-into-array-of-bytes-using-offset-on-stack:
6920     # . prologue
6921     55/push-ebp
6922     89/<- %ebp 4/r32/esp
6923     # setup
6924     (clear-stream _test-input-stream)
6925     (clear-stream $_test-input-buffered-file->buffer)
6926     (clear-stream _test-output-stream)
6927     (clear-stream $_test-output-buffered-file->buffer)
6928     #
6929     (write _test-input-stream "fn foo {\n")
6930     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
6931     (write _test-input-stream "  var idx: int\n")
6932     (write _test-input-stream "  var off/ecx: (offset byte) <- compute-offset arr, idx\n")
6933     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, off\n")
6934     (write _test-input-stream "}\n")
6935     # convert
6936     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
6937     (flush _test-output-buffered-file)
6938 #?     # dump _test-output-stream {{{
6939 #?     (write 2 "^")
6940 #?     (write-stream 2 _test-output-stream)
6941 #?     (write 2 "$\n")
6942 #?     (rewind-stream _test-output-stream)
6943 #?     # }}}
6944     # check output
6945     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/0")
6946     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/1")
6947     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/2")
6948     (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")
6949     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/4")
6950     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/5")
6951     (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")
6952     (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")
6953     (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")
6954     (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")
6955     (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")
6956     (check-next-stream-line-equal _test-output-stream "    (__check-mu-array-bounds %ecx 1 *eax \"foo\" \"arr\")"  "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/11")
6957     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %eax 0/imm32"  "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/12")
6958     (check-next-stream-line-equal _test-output-stream "    0f 84/jump-if-= __mu-abort-null-index-base-address/disp32"  "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/13")
6959     (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/14")
6960     (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/15")
6961     (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/16")
6962     (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/17")
6963     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/18")
6964     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/19")
6965     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/20")
6966     (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/21")
6967     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/22")
6968     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/23")
6969     # . epilogue
6970     89/<- %esp 5/r32/ebp
6971     5d/pop-to-ebp
6972     c3/return
6974 test-convert-function-and-type-definition:
6975     # . prologue
6976     55/push-ebp
6977     89/<- %ebp 4/r32/esp
6978     # setup
6979     (clear-stream _test-input-stream)
6980     (clear-stream $_test-input-buffered-file->buffer)
6981     (clear-stream _test-output-stream)
6982     (clear-stream $_test-output-buffered-file->buffer)
6983     #
6984     (write _test-input-stream "fn foo a: (addr t) {\n")
6985     (write _test-input-stream "  var _a/eax: (addr t) <- copy a\n")
6986     (write _test-input-stream "  var b/ecx: (addr int) <- get _a, x\n")
6987     (write _test-input-stream "  var c/ecx: (addr int) <- get _a, y\n")
6988     (write _test-input-stream "}\n")
6989     (write _test-input-stream "type t {\n")
6990     (write _test-input-stream "  x: int\n")
6991     (write _test-input-stream "  y: int\n")
6992     (write _test-input-stream "}\n")
6993     # convert
6994     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
6995     (flush _test-output-buffered-file)
6996 #?     # dump _test-output-stream {{{
6997 #?     (write 2 "^")
6998 #?     (write-stream 2 _test-output-stream)
6999 #?     (write 2 "$\n")
7000 #?     (rewind-stream _test-output-stream)
7001 #?     # }}}
7002     # check output
7003     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-and-type-definition/0")
7004     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-and-type-definition/1")
7005     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-and-type-definition/2")
7006     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-and-type-definition/3")
7007     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-and-type-definition/4")
7008     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-and-type-definition/5")
7009     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-function-and-type-definition/6")
7010     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-and-type-definition/7")
7011     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-and-type-definition/8")
7012     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %eax 0/imm32"  "F - test-convert-function-and-type-definition/9")
7013     (check-next-stream-line-equal _test-output-stream "    0f 84/jump-if-= __mu-abort-null-get-base-address/disp32"  "F - test-convert-function-and-type-definition/10")
7014     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000000) 0x00000001/r32"  "F - test-convert-function-and-type-definition/11")
7015     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %eax 0/imm32"  "F - test-convert-function-and-type-definition/12")
7016     (check-next-stream-line-equal _test-output-stream "    0f 84/jump-if-= __mu-abort-null-get-base-address/disp32"  "F - test-convert-function-and-type-definition/13")
7017     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000004) 0x00000001/r32"  "F - test-convert-function-and-type-definition/14")
7018     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-and-type-definition/15")
7019     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-convert-function-and-type-definition/16")
7020     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-and-type-definition/17")
7021     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-and-type-definition/18")
7022     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-and-type-definition/19")
7023     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-and-type-definition/20")
7024     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-and-type-definition/21")
7025     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-and-type-definition/22")
7026     # . epilogue
7027     89/<- %esp 5/r32/ebp
7028     5d/pop-to-ebp
7029     c3/return
7031 test-type-definition-with-array:
7032     # . prologue
7033     55/push-ebp
7034     89/<- %ebp 4/r32/esp
7035     # setup
7036     (clear-stream _test-input-stream)
7037     (clear-stream $_test-input-buffered-file->buffer)
7038     (clear-stream _test-output-stream)
7039     (clear-stream $_test-output-buffered-file->buffer)
7040     (clear-stream _test-error-stream)
7041     (clear-stream $_test-error-buffered-file->buffer)
7042     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
7043     68/push 0/imm32
7044     68/push 0/imm32
7045     89/<- %edx 4/r32/esp
7046     (tailor-exit-descriptor %edx 0x10)
7047     #
7048     (write _test-input-stream "type t {\n")
7049     (write _test-input-stream "  a: (array int 3)\n")
7050     (write _test-input-stream "}\n")
7051     # convert
7052     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
7053     # registers except esp clobbered at this point
7054     # restore ed
7055     89/<- %edx 4/r32/esp
7056     (flush _test-output-buffered-file)
7057     (flush _test-error-buffered-file)
7058 #?     # dump _test-error-stream {{{
7059 #?     (write 2 "^")
7060 #?     (write-stream 2 _test-error-stream)
7061 #?     (write 2 "$\n")
7062 #?     (rewind-stream _test-error-stream)
7063 #?     # }}}
7064     # check output
7065     (check-stream-equal _test-output-stream  ""  "F - test-type-definition-with-array: output should be empty")
7066     (check-next-stream-line-equal _test-error-stream  "type t: 'array' elements not allowed for now"  "F - test-type-definition-with-array: error message")
7067     # check that stop(1) was called
7068     (check-ints-equal *(edx+4) 2 "F - test-type-definition-with-array: exit status")
7069     # don't restore from ebp
7070     81 0/subop/add %esp 8/imm32
7071     # . epilogue
7072     5d/pop-to-ebp
7073     c3/return
7075 test-type-definition-with-addr:
7076     # . prologue
7077     55/push-ebp
7078     89/<- %ebp 4/r32/esp
7079     # setup
7080     (clear-stream _test-input-stream)
7081     (clear-stream $_test-input-buffered-file->buffer)
7082     (clear-stream _test-output-stream)
7083     (clear-stream $_test-output-buffered-file->buffer)
7084     (clear-stream _test-error-stream)
7085     (clear-stream $_test-error-buffered-file->buffer)
7086     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
7087     68/push 0/imm32
7088     68/push 0/imm32
7089     89/<- %edx 4/r32/esp
7090     (tailor-exit-descriptor %edx 0x10)
7091     #
7092     (write _test-input-stream "type t {\n")
7093     (write _test-input-stream "  a: (addr int)\n")
7094     (write _test-input-stream "}\n")
7095     # convert
7096     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
7097     # registers except esp clobbered at this point
7098     # restore ed
7099     89/<- %edx 4/r32/esp
7100     (flush _test-output-buffered-file)
7101     (flush _test-error-buffered-file)
7102 #?     # dump _test-error-stream {{{
7103 #?     (write 2 "^")
7104 #?     (write-stream 2 _test-error-stream)
7105 #?     (write 2 "$\n")
7106 #?     (rewind-stream _test-error-stream)
7107 #?     # }}}
7108     # check output
7109     (check-stream-equal _test-output-stream  ""  "F - test-type-definition-with-addr: output should be empty")
7110     (check-next-stream-line-equal _test-error-stream  "type t: 'addr' elements not allowed"  "F - test-type-definition-with-addr: error message")
7111     # check that stop(1) was called
7112     (check-ints-equal *(edx+4) 2 "F - test-type-definition-with-addr: exit status")
7113     # don't restore from ebp
7114     81 0/subop/add %esp 8/imm32
7115     # . epilogue
7116     5d/pop-to-ebp
7117     c3/return
7119 test-convert-function-with-local-var-with-user-defined-type:
7120     # . prologue
7121     55/push-ebp
7122     89/<- %ebp 4/r32/esp
7123     # setup
7124     (clear-stream _test-input-stream)
7125     (clear-stream $_test-input-buffered-file->buffer)
7126     (clear-stream _test-output-stream)
7127     (clear-stream $_test-output-buffered-file->buffer)
7128     #
7129     (write _test-input-stream "fn foo {\n")
7130     (write _test-input-stream "  var a: t\n")
7131     (write _test-input-stream "}\n")
7132     (write _test-input-stream "type t {\n")
7133     (write _test-input-stream "  x: int\n")
7134     (write _test-input-stream "  y: int\n")
7135     (write _test-input-stream "}\n")
7136     # convert
7137     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
7138     (flush _test-output-buffered-file)
7139 #?     # dump _test-output-stream {{{
7140 #?     (write 2 "^")
7141 #?     (write-stream 2 _test-output-stream)
7142 #?     (write 2 "$\n")
7143 #?     (rewind-stream _test-output-stream)
7144 #?     # }}}
7145     # check output
7146     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-user-defined-type/0")
7147     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-user-defined-type/1")
7148     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-user-defined-type/2")
7149     (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")
7150     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-user-defined-type/4")
7151     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-user-defined-type/5")
7152     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/6")
7153     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/7")
7154     (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")
7155     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-user-defined-type/9")
7156     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-user-defined-type/10")
7157     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-user-defined-type/11")
7158     (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")
7159     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-with-user-defined-type/13")
7160     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-user-defined-type/14")
7161     # . epilogue
7162     89/<- %esp 5/r32/ebp
7163     5d/pop-to-ebp
7164     c3/return
7166 test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type:
7167     # . prologue
7168     55/push-ebp
7169     89/<- %ebp 4/r32/esp
7170     # setup
7171     (clear-stream _test-input-stream)
7172     (clear-stream $_test-input-buffered-file->buffer)
7173     (clear-stream _test-output-stream)
7174     (clear-stream $_test-output-buffered-file->buffer)
7175     #
7176     (write _test-input-stream "fn foo {\n")
7177     (write _test-input-stream "  var a: t\n")
7178     (write _test-input-stream "}\n")
7179     (write _test-input-stream "type t {\n")
7180     (write _test-input-stream "  x: s\n")
7181     (write _test-input-stream "}\n")
7182     (write _test-input-stream "type s {\n")
7183     (write _test-input-stream "  z: int\n")
7184     (write _test-input-stream "}\n")
7185     # convert
7186     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
7187     (flush _test-output-buffered-file)
7188 #?     # dump _test-output-stream {{{
7189 #?     (write 2 "^")
7190 #?     (write-stream 2 _test-output-stream)
7191 #?     (write 2 "$\n")
7192 #?     (rewind-stream _test-output-stream)
7193 #?     # }}}
7194     # check output
7195     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/0")
7196     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/1")
7197     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/2")
7198     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/3")
7199     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/4")
7200     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/5")
7201     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/7")
7202     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/8")
7203     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/9")
7204     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/10")
7205     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/11")
7206     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/12")
7207     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/13")
7208     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/14")
7209     # . epilogue
7210     89/<- %esp 5/r32/ebp
7211     5d/pop-to-ebp
7212     c3/return
7214 test-convert-function-call-with-arg-of-user-defined-type:
7215     # . prologue
7216     55/push-ebp
7217     89/<- %ebp 4/r32/esp
7218     # setup
7219     (clear-stream _test-input-stream)
7220     (clear-stream $_test-input-buffered-file->buffer)
7221     (clear-stream _test-output-stream)
7222     (clear-stream $_test-output-buffered-file->buffer)
7223     #
7224     (write _test-input-stream "fn f {\n")
7225     (write _test-input-stream "  var a: t\n")
7226     (write _test-input-stream "  foo a\n")
7227     (write _test-input-stream "}\n")
7228     (write _test-input-stream "fn foo x: t {\n")
7229     (write _test-input-stream "}\n")
7230     (write _test-input-stream "type t {\n")
7231     (write _test-input-stream "  x: int\n")
7232     (write _test-input-stream "  y: int\n")
7233     (write _test-input-stream "}\n")
7234     # convert
7235     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
7236     (flush _test-output-buffered-file)
7237 #?     # dump _test-output-stream {{{
7238 #?     (write 2 "^")
7239 #?     (write-stream 2 _test-output-stream)
7240 #?     (write 2 "$\n")
7241 #?     (rewind-stream _test-output-stream)
7242 #?     # }}}
7243     # check output
7244     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
7245     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
7246     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
7247     (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")
7248     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
7249     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
7250     # var a: t
7251     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/6")
7252     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/7")
7253     # foo a
7254     (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")
7255     #
7256     (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")
7257     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
7258     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
7259     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
7260     (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")
7261     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
7262     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
7263     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
7264     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
7265     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
7266     (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")
7267     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
7268     (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")
7269     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
7270     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
7271     # . epilogue
7272     89/<- %esp 5/r32/ebp
7273     5d/pop-to-ebp
7274     c3/return
7276 test-convert-function-call-with-arg-of-user-defined-type-register-indirect:
7277     # . prologue
7278     55/push-ebp
7279     89/<- %ebp 4/r32/esp
7280     # setup
7281     (clear-stream _test-input-stream)
7282     (clear-stream $_test-input-buffered-file->buffer)
7283     (clear-stream _test-output-stream)
7284     (clear-stream $_test-output-buffered-file->buffer)
7285     #
7286     (write _test-input-stream "fn f {\n")
7287     (write _test-input-stream "  var a/eax: (addr t) <- copy 0\n")
7288     (write _test-input-stream "  foo *a\n")
7289     (write _test-input-stream "}\n")
7290     (write _test-input-stream "fn foo x: t {\n")
7291     (write _test-input-stream "}\n")
7292     (write _test-input-stream "type t {\n")
7293     (write _test-input-stream "  x: int\n")
7294     (write _test-input-stream "  y: int\n")
7295     (write _test-input-stream "}\n")
7296     # convert
7297     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
7298     (flush _test-output-buffered-file)
7299 #?     # dump _test-output-stream {{{
7300 #?     (write 2 "^")
7301 #?     (write-stream 2 _test-output-stream)
7302 #?     (write 2 "$\n")
7303 #?     (rewind-stream _test-output-stream)
7304 #?     # }}}
7305     # check output
7306     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
7307     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
7308     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
7309     (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")
7310     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
7311     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
7312     # var a
7313     (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")
7314     (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")
7315     # foo a
7316     (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")
7317     #
7318     (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")
7319     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
7320     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
7321     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
7322     (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")
7323     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
7324     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
7325     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
7326     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
7327     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
7328     (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")
7329     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
7330     (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")
7331     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
7332     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
7333     # . epilogue
7334     89/<- %esp 5/r32/ebp
7335     5d/pop-to-ebp
7336     c3/return
7338 # we don't have special support for call-by-reference; just explicitly create
7339 # a new variable with the address of the arg
7340 test-convert-function-call-with-arg-of-user-defined-type-by-reference:
7341     # . prologue
7342     55/push-ebp
7343     89/<- %ebp 4/r32/esp
7344     # setup
7345     (clear-stream _test-input-stream)
7346     (clear-stream $_test-input-buffered-file->buffer)
7347     (clear-stream _test-output-stream)
7348     (clear-stream $_test-output-buffered-file->buffer)
7349     #
7350     (write _test-input-stream "fn f {\n")
7351     (write _test-input-stream "  var a: t\n")
7352     (write _test-input-stream "  var b/eax: (addr t) <- address a\n")
7353     (write _test-input-stream "  foo b\n")
7354     (write _test-input-stream "}\n")
7355     (write _test-input-stream "fn foo x: (addr t) {\n")
7356     (write _test-input-stream "  var x/ecx: (addr t) <- copy x\n")
7357     (write _test-input-stream "}\n")
7358     (write _test-input-stream "type t {\n")
7359     (write _test-input-stream "  x: int\n")
7360     (write _test-input-stream "  y: int\n")
7361     (write _test-input-stream "}\n")
7362     # convert
7363     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
7364     (flush _test-output-buffered-file)
7365 #?     # dump _test-output-stream {{{
7366 #?     (write 2 "^")
7367 #?     (write-stream 2 _test-output-stream)
7368 #?     (write 2 "$\n")
7369 #?     (rewind-stream _test-output-stream)
7370 #?     # }}}
7371     # check output
7372     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/0")
7373     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/1")
7374     (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")
7375     (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")
7376     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/4")
7377     (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")
7378     # var a: t
7379     (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")
7380     (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")
7381     # var b/eax: (addr t)
7382     (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")
7383     (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")
7384     # foo a
7385     (check-next-stream-line-equal _test-output-stream "    (foo %eax)"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/10")
7386     #
7387     (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")
7388     (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")
7389     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/13")
7390     (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")
7391     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/15")
7392     (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")
7393     (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")
7394     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/18")
7395     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/19")
7396     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/20")
7397     (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")
7398     (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")
7399     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/23")
7400     (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")
7401     (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")
7402     (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")
7403     (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/27")
7404     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/28")
7405     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/29")
7406     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/30")
7407     (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/31")
7408     (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/32")
7409     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/33")
7410     # . epilogue
7411     89/<- %esp 5/r32/ebp
7412     5d/pop-to-ebp
7413     c3/return
7415 test-convert-get-on-local-variable:
7416     # . prologue
7417     55/push-ebp
7418     89/<- %ebp 4/r32/esp
7419     # setup
7420     (clear-stream _test-input-stream)
7421     (clear-stream $_test-input-buffered-file->buffer)
7422     (clear-stream _test-output-stream)
7423     (clear-stream $_test-output-buffered-file->buffer)
7424     #
7425     (write _test-input-stream "fn foo {\n")
7426     (write _test-input-stream "  var a: t\n")
7427     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
7428     (write _test-input-stream "}\n")
7429     (write _test-input-stream "type t {\n")
7430     (write _test-input-stream "  x: int\n")
7431     (write _test-input-stream "  y: int\n")
7432     (write _test-input-stream "}\n")
7433     # convert
7434     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
7435     (flush _test-output-buffered-file)
7436 #?     # dump _test-output-stream {{{
7437 #?     (write 2 "^")
7438 #?     (write-stream 2 _test-output-stream)
7439 #?     (write 2 "$\n")
7440 #?     (rewind-stream _test-output-stream)
7441 #?     # }}}
7442     # check output
7443     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-local-variable/0")
7444     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-local-variable/1")
7445     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-local-variable/2")
7446     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-local-variable/3")
7447     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-local-variable/4")
7448     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-local-variable/5")
7449     # var a
7450     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/6")
7451     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/7")
7452     # var c
7453     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-local-variable/8")
7454     # get
7455     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000001/r32"  "F - test-convert-get-on-local-variable/9")
7456     # reclaim c
7457     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-local-variable/10")
7458     # reclaim a
7459     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000008/imm32"  "F - test-convert-get-on-local-variable/11")
7460     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-local-variable/12")
7461     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-local-variable/13")
7462     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-local-variable/14")
7463     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-local-variable/15")
7464     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-local-variable/16")
7465     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-local-variable/17")
7466     # . epilogue
7467     89/<- %esp 5/r32/ebp
7468     5d/pop-to-ebp
7469     c3/return
7471 test-convert-get-on-function-argument:
7472     # . prologue
7473     55/push-ebp
7474     89/<- %ebp 4/r32/esp
7475     # setup
7476     (clear-stream _test-input-stream)
7477     (clear-stream $_test-input-buffered-file->buffer)
7478     (clear-stream _test-output-stream)
7479     (clear-stream $_test-output-buffered-file->buffer)
7480     #
7481     (write _test-input-stream "fn foo a: t {\n")
7482     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
7483     (write _test-input-stream "}\n")
7484     (write _test-input-stream "type t {\n")
7485     (write _test-input-stream "  x: int\n")
7486     (write _test-input-stream "  y: int\n")
7487     (write _test-input-stream "}\n")
7488     # convert
7489     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
7490     (flush _test-output-buffered-file)
7491 #?     # dump _test-output-stream {{{
7492 #?     (write 2 "^")
7493 #?     (write-stream 2 _test-output-stream)
7494 #?     (write 2 "$\n")
7495 #?     (rewind-stream _test-output-stream)
7496 #?     # }}}
7497     # check output
7498     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument/0")
7499     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument/1")
7500     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument/2")
7501     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument/3")
7502     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument/4")
7503     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument/5")
7504     # var c
7505     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument/6")
7506     # get
7507     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0x0000000c) 0x00000001/r32"  "F - test-convert-get-on-function-argument/7")
7508     # reclaim c
7509     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument/8")
7510     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument/9")
7511     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument/10")
7512     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument/11")
7513     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument/12")
7514     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument/13")
7515     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument/14")
7516     # . epilogue
7517     89/<- %esp 5/r32/ebp
7518     5d/pop-to-ebp
7519     c3/return
7521 test-convert-get-on-function-argument-with-known-type:
7522     # . prologue
7523     55/push-ebp
7524     89/<- %ebp 4/r32/esp
7525     # setup
7526     (clear-stream _test-input-stream)
7527     (clear-stream $_test-input-buffered-file->buffer)
7528     (clear-stream _test-output-stream)
7529     (clear-stream $_test-output-buffered-file->buffer)
7530     #
7531     (write _test-input-stream "type t {\n")
7532     (write _test-input-stream "  x: int\n")
7533     (write _test-input-stream "  y: int\n")
7534     (write _test-input-stream "}\n")
7535     (write _test-input-stream "fn foo a: t {\n")
7536     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
7537     (write _test-input-stream "}\n")
7538     # convert
7539     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
7540     (flush _test-output-buffered-file)
7541 #?     # dump _test-output-stream {{{
7542 #?     (write 2 "^")
7543 #?     (write-stream 2 _test-output-stream)
7544 #?     (write 2 "$\n")
7545 #?     (rewind-stream _test-output-stream)
7546 #?     # }}}
7547     # check output
7548     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument-with-known-type/0")
7549     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument-with-known-type/1")
7550     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument-with-known-type/2")
7551     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument-with-known-type/3")
7552     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument-with-known-type/4")
7553     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument-with-known-type/5")
7554     # var c
7555     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument-with-known-type/6")
7556     # get
7557     (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")
7558     # reclaim c
7559     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument-with-known-type/8")
7560     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument-with-known-type/9")
7561     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument-with-known-type/10")
7562     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument-with-known-type/11")
7563     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument-with-known-type/12")
7564     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument-with-known-type/13")
7565     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument-with-known-type/14")
7566     # . epilogue
7567     89/<- %esp 5/r32/ebp
7568     5d/pop-to-ebp
7569     c3/return
7571 test-add-with-too-many-inouts:
7572     # . prologue
7573     55/push-ebp
7574     89/<- %ebp 4/r32/esp
7575     # setup
7576     (clear-stream _test-input-stream)
7577     (clear-stream $_test-input-buffered-file->buffer)
7578     (clear-stream _test-output-stream)
7579     (clear-stream $_test-output-buffered-file->buffer)
7580     (clear-stream _test-error-stream)
7581     (clear-stream $_test-error-buffered-file->buffer)
7582     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
7583     68/push 0/imm32
7584     68/push 0/imm32
7585     89/<- %edx 4/r32/esp
7586     (tailor-exit-descriptor %edx 0x10)
7587     #
7588     (write _test-input-stream "fn foo {\n")
7589     (write _test-input-stream "  var a: int\n")
7590     (write _test-input-stream "  var b/ecx: int <- add a, 0\n")
7591     (write _test-input-stream "}\n")
7592     # convert
7593     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
7594     # registers except esp clobbered at this point
7595     # restore ed
7596     89/<- %edx 4/r32/esp
7597     (flush _test-output-buffered-file)
7598     (flush _test-error-buffered-file)
7599 #?     # dump _test-error-stream {{{
7600 #?     (write 2 "^")
7601 #?     (write-stream 2 _test-error-stream)
7602 #?     (write 2 "$\n")
7603 #?     (rewind-stream _test-error-stream)
7604 #?     # }}}
7605     # check output
7606     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-inouts: output should be empty")
7607     (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")
7608     # check that stop(1) was called
7609     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-inouts: exit status")
7610     # don't restore from ebp
7611     81 0/subop/add %esp 8/imm32
7612     # . epilogue
7613     5d/pop-to-ebp
7614     c3/return
7616 test-add-with-too-many-inouts-2:
7617     # . prologue
7618     55/push-ebp
7619     89/<- %ebp 4/r32/esp
7620     # setup
7621     (clear-stream _test-input-stream)
7622     (clear-stream $_test-input-buffered-file->buffer)
7623     (clear-stream _test-output-stream)
7624     (clear-stream $_test-output-buffered-file->buffer)
7625     (clear-stream _test-error-stream)
7626     (clear-stream $_test-error-buffered-file->buffer)
7627     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
7628     68/push 0/imm32
7629     68/push 0/imm32
7630     89/<- %edx 4/r32/esp
7631     (tailor-exit-descriptor %edx 0x10)
7632     #
7633     (write _test-input-stream "fn foo {\n")
7634     (write _test-input-stream "  var a: int\n")
7635     (write _test-input-stream "  add-to a, 0, 1\n")
7636     (write _test-input-stream "}\n")
7637     # convert
7638     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
7639     # registers except esp clobbered at this point
7640     # restore ed
7641     89/<- %edx 4/r32/esp
7642     (flush _test-output-buffered-file)
7643     (flush _test-error-buffered-file)
7644 #?     # dump _test-error-stream {{{
7645 #?     (write 2 "^")
7646 #?     (write-stream 2 _test-error-stream)
7647 #?     (write 2 "$\n")
7648 #?     (rewind-stream _test-error-stream)
7649 #?     # }}}
7650     # check output
7651     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-inouts-2: output should be empty")
7652     (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")
7653     # check that stop(1) was called
7654     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-inouts-2: exit status")
7655     # don't restore from ebp
7656     81 0/subop/add %esp 8/imm32
7657     # . epilogue
7658     5d/pop-to-ebp
7659     c3/return
7661 test-add-with-too-many-outputs:
7662     # . prologue
7663     55/push-ebp
7664     89/<- %ebp 4/r32/esp
7665     # setup
7666     (clear-stream _test-input-stream)
7667     (clear-stream $_test-input-buffered-file->buffer)
7668     (clear-stream _test-output-stream)
7669     (clear-stream $_test-output-buffered-file->buffer)
7670     (clear-stream _test-error-stream)
7671     (clear-stream $_test-error-buffered-file->buffer)
7672     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
7673     68/push 0/imm32
7674     68/push 0/imm32
7675     89/<- %edx 4/r32/esp
7676     (tailor-exit-descriptor %edx 0x10)
7677     #
7678     (write _test-input-stream "fn foo {\n")
7679     (write _test-input-stream "  var a/eax: int <- copy 0\n")
7680     (write _test-input-stream "  var b/ebx: int <- copy 0\n")
7681     (write _test-input-stream "  var c/ecx: int <- copy 0\n")
7682     (write _test-input-stream "  c, b <- add a\n")
7683     (write _test-input-stream "}\n")
7684     # convert
7685     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
7686     # registers except esp clobbered at this point
7687     # restore ed
7688     89/<- %edx 4/r32/esp
7689     (flush _test-output-buffered-file)
7690     (flush _test-error-buffered-file)
7691 #?     # dump _test-error-stream {{{
7692 #?     (write 2 "^")
7693 #?     (write-stream 2 _test-error-stream)
7694 #?     (write 2 "$\n")
7695 #?     (rewind-stream _test-error-stream)
7696 #?     # }}}
7697     # check output
7698     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-outputs: output should be empty")
7699     (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")
7700     # check that stop(1) was called
7701     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-outputs: exit status")
7702     # don't restore from ebp
7703     81 0/subop/add %esp 8/imm32
7704     # . epilogue
7705     5d/pop-to-ebp
7706     c3/return
7708 test-add-with-non-number:
7709     # . prologue
7710     55/push-ebp
7711     89/<- %ebp 4/r32/esp
7712     # setup
7713     (clear-stream _test-input-stream)
7714     (clear-stream $_test-input-buffered-file->buffer)
7715     (clear-stream _test-output-stream)
7716     (clear-stream $_test-output-buffered-file->buffer)
7717     (clear-stream _test-error-stream)
7718     (clear-stream $_test-error-buffered-file->buffer)
7719     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
7720     68/push 0/imm32
7721     68/push 0/imm32
7722     89/<- %edx 4/r32/esp
7723     (tailor-exit-descriptor %edx 0x10)
7724     #
7725     (write _test-input-stream "fn foo {\n")
7726     (write _test-input-stream "  var a: int\n")
7727     (write _test-input-stream "  var b/ecx: (addr int) <- add a\n")
7728     (write _test-input-stream "}\n")
7729     # convert
7730     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
7731     # registers except esp clobbered at this point
7732     # restore ed
7733     89/<- %edx 4/r32/esp
7734     (flush _test-output-buffered-file)
7735     (flush _test-error-buffered-file)
7736 #?     # dump _test-error-stream {{{
7737 #?     (write 2 "^")
7738 #?     (write-stream 2 _test-error-stream)
7739 #?     (write 2 "$\n")
7740 #?     (rewind-stream _test-error-stream)
7741 #?     # }}}
7742     # check output
7743     (check-stream-equal _test-output-stream  ""  "F - test-add-with-non-number: output should be empty")
7744     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt add: 'b' must be a non-addr non-offset scalar"  "F - test-add-with-non-number: error message")
7745     # check that stop(1) was called
7746     (check-ints-equal *(edx+4) 2 "F - test-add-with-non-number: exit status")
7747     # don't restore from ebp
7748     81 0/subop/add %esp 8/imm32
7749     # . epilogue
7750     5d/pop-to-ebp
7751     c3/return
7753 test-add-with-addr-dereferenced:
7754     # . prologue
7755     55/push-ebp
7756     89/<- %ebp 4/r32/esp
7757     # setup
7758     (clear-stream _test-input-stream)
7759     (clear-stream $_test-input-buffered-file->buffer)
7760     (clear-stream _test-output-stream)
7761     (clear-stream $_test-output-buffered-file->buffer)
7762     #
7763     (write _test-input-stream "fn foo {\n")
7764     (write _test-input-stream "  var a/eax: (addr int) <- copy 0\n")
7765     (write _test-input-stream "  add-to *a, 1\n")
7766     (write _test-input-stream "}\n")
7767     # convert
7768     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
7769     (flush _test-output-buffered-file)
7770     # no error
7771     # . epilogue
7772     89/<- %esp 5/r32/ebp
7773     5d/pop-to-ebp
7774     c3/return
7776 test-copy-with-no-inout:
7777     # . prologue
7778     55/push-ebp
7779     89/<- %ebp 4/r32/esp
7780     # setup
7781     (clear-stream _test-input-stream)
7782     (clear-stream $_test-input-buffered-file->buffer)
7783     (clear-stream _test-output-stream)
7784     (clear-stream $_test-output-buffered-file->buffer)
7785     (clear-stream _test-error-stream)
7786     (clear-stream $_test-error-buffered-file->buffer)
7787     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
7788     68/push 0/imm32
7789     68/push 0/imm32
7790     89/<- %edx 4/r32/esp
7791     (tailor-exit-descriptor %edx 0x10)
7792     #
7793     (write _test-input-stream "fn foo {\n")
7794     (write _test-input-stream "  var x/eax: boolean <- copy\n")
7795     (write _test-input-stream "}\n")
7796     # convert
7797     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
7798     # registers except esp clobbered at this point
7799     # restore ed
7800     89/<- %edx 4/r32/esp
7801     (flush _test-output-buffered-file)
7802     (flush _test-error-buffered-file)
7803 #?     # dump _test-error-stream {{{
7804 #?     (write 2 "^")
7805 #?     (write-stream 2 _test-error-stream)
7806 #?     (write 2 "$\n")
7807 #?     (rewind-stream _test-error-stream)
7808 #?     # }}}
7809     # check output
7810     (check-stream-equal _test-output-stream  ""  "F - test-copy-with-no-inout: output should be empty")
7811     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'copy' expects an inout"  "F - test-copy-with-no-inout: error message")
7812     # check that stop(1) was called
7813     (check-ints-equal *(edx+4) 2 "F - test-copy-with-no-inout: exit status")
7814     # don't restore from ebp
7815     81 0/subop/add %esp 8/imm32
7816     # . epilogue
7817     5d/pop-to-ebp
7818     c3/return
7820 test-copy-with-multiple-inouts:
7821     # . prologue
7822     55/push-ebp
7823     89/<- %ebp 4/r32/esp
7824     # setup
7825     (clear-stream _test-input-stream)
7826     (clear-stream $_test-input-buffered-file->buffer)
7827     (clear-stream _test-output-stream)
7828     (clear-stream $_test-output-buffered-file->buffer)
7829     (clear-stream _test-error-stream)
7830     (clear-stream $_test-error-buffered-file->buffer)
7831     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
7832     68/push 0/imm32
7833     68/push 0/imm32
7834     89/<- %edx 4/r32/esp
7835     (tailor-exit-descriptor %edx 0x10)
7836     #
7837     (write _test-input-stream "fn foo {\n")
7838     (write _test-input-stream "  var x/eax: boolean <- copy 0, 0\n")
7839     (write _test-input-stream "}\n")
7840     # convert
7841     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
7842     # registers except esp clobbered at this point
7843     # restore ed
7844     89/<- %edx 4/r32/esp
7845     (flush _test-output-buffered-file)
7846     (flush _test-error-buffered-file)
7847 #?     # dump _test-error-stream {{{
7848 #?     (write 2 "^")
7849 #?     (write-stream 2 _test-error-stream)
7850 #?     (write 2 "$\n")
7851 #?     (rewind-stream _test-error-stream)
7852 #?     # }}}
7853     # check output
7854     (check-stream-equal _test-output-stream  ""  "F - test-copy-with-multiple-inouts: output should be empty")
7855     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'copy' must have just one inout"  "F - test-copy-with-multiple-inouts: error message")
7856     # check that stop(1) was called
7857     (check-ints-equal *(edx+4) 2 "F - test-copy-with-multiple-inouts: exit status")
7858     # don't restore from ebp
7859     81 0/subop/add %esp 8/imm32
7860     # . epilogue
7861     5d/pop-to-ebp
7862     c3/return
7864 test-copy-with-no-output:
7865     # . prologue
7866     55/push-ebp
7867     89/<- %ebp 4/r32/esp
7868     # setup
7869     (clear-stream _test-input-stream)
7870     (clear-stream $_test-input-buffered-file->buffer)
7871     (clear-stream _test-output-stream)
7872     (clear-stream $_test-output-buffered-file->buffer)
7873     (clear-stream _test-error-stream)
7874     (clear-stream $_test-error-buffered-file->buffer)
7875     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
7876     68/push 0/imm32
7877     68/push 0/imm32
7878     89/<- %edx 4/r32/esp
7879     (tailor-exit-descriptor %edx 0x10)
7880     #
7881     (write _test-input-stream "fn foo {\n")
7882     (write _test-input-stream "  copy 0\n")
7883     (write _test-input-stream "}\n")
7884     # convert
7885     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
7886     # registers except esp clobbered at this point
7887     # restore ed
7888     89/<- %edx 4/r32/esp
7889     (flush _test-output-buffered-file)
7890     (flush _test-error-buffered-file)
7891 #?     # dump _test-error-stream {{{
7892 #?     (write 2 "^")
7893 #?     (write-stream 2 _test-error-stream)
7894 #?     (write 2 "$\n")
7895 #?     (rewind-stream _test-error-stream)
7896 #?     # }}}
7897     # check output
7898     (check-stream-equal _test-output-stream  ""  "F - test-copy-with-no-output: output should be empty")
7899     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'copy' expects an output"  "F - test-copy-with-no-output: error message")
7900     # check that stop(1) was called
7901     (check-ints-equal *(edx+4) 2 "F - test-copy-with-no-output: exit status")
7902     # don't restore from ebp
7903     81 0/subop/add %esp 8/imm32
7904     # . epilogue
7905     5d/pop-to-ebp
7906     c3/return
7908 test-copy-with-multiple-outputs:
7909     # . prologue
7910     55/push-ebp
7911     89/<- %ebp 4/r32/esp
7912     # setup
7913     (clear-stream _test-input-stream)
7914     (clear-stream $_test-input-buffered-file->buffer)
7915     (clear-stream _test-output-stream)
7916     (clear-stream $_test-output-buffered-file->buffer)
7917     (clear-stream _test-error-stream)
7918     (clear-stream $_test-error-buffered-file->buffer)
7919     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
7920     68/push 0/imm32
7921     68/push 0/imm32
7922     89/<- %edx 4/r32/esp
7923     (tailor-exit-descriptor %edx 0x10)
7924     #
7925     (write _test-input-stream "fn foo {\n")
7926     (write _test-input-stream "  var x/eax: boolean <- copy 0\n")
7927     (write _test-input-stream "  var y/ecx: boolean <- copy 0\n")
7928     (write _test-input-stream "  x, y <- copy 0\n")
7929     (write _test-input-stream "}\n")
7930     # convert
7931     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
7932     # registers except esp clobbered at this point
7933     # restore ed
7934     89/<- %edx 4/r32/esp
7935     (flush _test-output-buffered-file)
7936     (flush _test-error-buffered-file)
7937 #?     # dump _test-error-stream {{{
7938 #?     (write 2 "^")
7939 #?     (write-stream 2 _test-error-stream)
7940 #?     (write 2 "$\n")
7941 #?     (rewind-stream _test-error-stream)
7942 #?     # }}}
7943     # check output
7944     (check-stream-equal _test-output-stream  ""  "F - test-copy-with-multiple-outputs: output should be empty")
7945     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'copy' must have just one output"  "F - test-copy-with-multiple-outputs: error message")
7946     # check that stop(1) was called
7947     (check-ints-equal *(edx+4) 2 "F - test-copy-with-multiple-outputs: exit status")
7948     # don't restore from ebp
7949     81 0/subop/add %esp 8/imm32
7950     # . epilogue
7951     5d/pop-to-ebp
7952     c3/return
7954 test-copy-invalid-value-to-address:
7955     # . prologue
7956     55/push-ebp
7957     89/<- %ebp 4/r32/esp
7958     # setup
7959     (clear-stream _test-input-stream)
7960     (clear-stream $_test-input-buffered-file->buffer)
7961     (clear-stream _test-output-stream)
7962     (clear-stream $_test-output-buffered-file->buffer)
7963     (clear-stream _test-error-stream)
7964     (clear-stream $_test-error-buffered-file->buffer)
7965     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
7966     68/push 0/imm32
7967     68/push 0/imm32
7968     89/<- %edx 4/r32/esp
7969     (tailor-exit-descriptor %edx 0x10)
7970     #
7971     (write _test-input-stream "fn foo {\n")
7972     (write _test-input-stream "  var x/eax: int <- copy 0\n")
7973     (write _test-input-stream "  var y/ecx: (addr int) <- copy x\n")
7974     (write _test-input-stream "}\n")
7975     # convert
7976     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
7977     # registers except esp clobbered at this point
7978     # restore ed
7979     89/<- %edx 4/r32/esp
7980     (flush _test-output-buffered-file)
7981     (flush _test-error-buffered-file)
7982 #?     # dump _test-error-stream {{{
7983 #?     (write 2 "^")
7984 #?     (write-stream 2 _test-error-stream)
7985 #?     (write 2 "$\n")
7986 #?     (rewind-stream _test-error-stream)
7987 #?     # }}}
7988     # check output
7989     (check-stream-equal _test-output-stream  ""  "F - test-copy-invalid-value-to-address: output should be empty")
7990     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt copy: 'y' must be a non-addr non-offset scalar"  "F - test-copy-invalid-value-to-address: error message")
7991     # check that stop(1) was called
7992     (check-ints-equal *(edx+4) 2 "F - test-copy-invalid-value-to-address: exit status")
7993     # don't restore from ebp
7994     81 0/subop/add %esp 8/imm32
7995     # . epilogue
7996     5d/pop-to-ebp
7997     c3/return
7999 test-copy-null-value-to-address:
8000     # . prologue
8001     55/push-ebp
8002     89/<- %ebp 4/r32/esp
8003     # setup
8004     (clear-stream _test-input-stream)
8005     (clear-stream $_test-input-buffered-file->buffer)
8006     (clear-stream _test-output-stream)
8007     (clear-stream $_test-output-buffered-file->buffer)
8008     #
8009     (write _test-input-stream "fn foo {\n")
8010     (write _test-input-stream "  var y/ecx: (addr int) <- copy 0\n")
8011     (write _test-input-stream "}\n")
8012     # convert
8013     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
8014     (flush _test-output-buffered-file)
8015     # no errors
8016     # . epilogue
8017     89/<- %esp 5/r32/ebp
8018     5d/pop-to-ebp
8019     c3/return
8021 test-copy-string-literal:
8022     # . prologue
8023     55/push-ebp
8024     89/<- %ebp 4/r32/esp
8025     # setup
8026     (clear-stream _test-input-stream)
8027     (clear-stream $_test-input-buffered-file->buffer)
8028     (clear-stream _test-output-stream)
8029     (clear-stream $_test-output-buffered-file->buffer)
8030     #
8031     (write _test-input-stream "fn foo {\n")
8032     (write _test-input-stream "  var y/ecx: (addr array byte) <- copy \"a\"\n")
8033     (write _test-input-stream "}\n")
8034     # convert
8035     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
8036     (flush _test-output-buffered-file)
8037     # no errors
8038 #?     # dump _test-output-stream {{{
8039 #?     (write 2 "^")
8040 #?     (write-stream 2 _test-output-stream)
8041 #?     (write 2 "$\n")
8042 #?     (rewind-stream _test-output-stream)
8043 #?     # }}}
8044     # check output
8045     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-copy-string-literal/0")
8046     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-copy-string-literal/1")
8047     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-copy-string-literal/2")
8048     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-copy-string-literal/3")
8049     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-copy-string-literal/4")
8050     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-copy-string-literal/5")
8051     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-copy-string-literal/6")
8052     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx \"a\"/imm32"  "F - test-copy-string-literal/7")
8053     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-copy-string-literal/8")
8054     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-copy-string-literal/9")
8055     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-copy-string-literal/10")
8056     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-copy-string-literal/11")
8057     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-copy-string-literal/12")
8058     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-copy-string-literal/13")
8059     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-copy-string-literal/14")
8060     # . epilogue
8061     89/<- %esp 5/r32/ebp
8062     5d/pop-to-ebp
8063     c3/return
8065 test-copy-invalid-value-to-offset:
8066     # . prologue
8067     55/push-ebp
8068     89/<- %ebp 4/r32/esp
8069     # setup
8070     (clear-stream _test-input-stream)
8071     (clear-stream $_test-input-buffered-file->buffer)
8072     (clear-stream _test-output-stream)
8073     (clear-stream $_test-output-buffered-file->buffer)
8074     (clear-stream _test-error-stream)
8075     (clear-stream $_test-error-buffered-file->buffer)
8076     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
8077     68/push 0/imm32
8078     68/push 0/imm32
8079     89/<- %edx 4/r32/esp
8080     (tailor-exit-descriptor %edx 0x10)
8081     #
8082     (write _test-input-stream "fn foo {\n")
8083     (write _test-input-stream "  var x/eax: int <- copy 0\n")
8084     (write _test-input-stream "  var y/ecx: (offset int) <- copy x\n")
8085     (write _test-input-stream "}\n")
8086     # convert
8087     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
8088     # registers except esp clobbered at this point
8089     # restore ed
8090     89/<- %edx 4/r32/esp
8091     (flush _test-output-buffered-file)
8092     (flush _test-error-buffered-file)
8093 #?     # dump _test-error-stream {{{
8094 #?     (write 2 "^")
8095 #?     (write-stream 2 _test-error-stream)
8096 #?     (write 2 "$\n")
8097 #?     (rewind-stream _test-error-stream)
8098 #?     # }}}
8099     # check output
8100     (check-stream-equal _test-output-stream  ""  "F - test-copy-invalid-value-to-address: output should be empty")
8101     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt copy: 'y' must be a non-addr non-offset scalar"  "F - test-copy-invalid-value-to-address: error message")
8102     # check that stop(1) was called
8103     (check-ints-equal *(edx+4) 2 "F - test-copy-invalid-value-to-offset: exit status")
8104     # don't restore from ebp
8105     81 0/subop/add %esp 8/imm32
8106     # . epilogue
8107     5d/pop-to-ebp
8108     c3/return
8110 test-copy-null-value-to-offset:
8111     # . prologue
8112     55/push-ebp
8113     89/<- %ebp 4/r32/esp
8114     # setup
8115     (clear-stream _test-input-stream)
8116     (clear-stream $_test-input-buffered-file->buffer)
8117     (clear-stream _test-output-stream)
8118     (clear-stream $_test-output-buffered-file->buffer)
8119     #
8120     (write _test-input-stream "fn foo {\n")
8121     (write _test-input-stream "  var y/ecx: (offset int) <- copy 0\n")
8122     (write _test-input-stream "}\n")
8123     # convert
8124     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
8125     (flush _test-output-buffered-file)
8126 #?     # dump _test-error-stream {{{
8127 #?     (write 2 "^")
8128 #?     (write-stream 2 _test-error-stream)
8129 #?     (write 2 "$\n")
8130 #?     (rewind-stream _test-error-stream)
8131 #?     # }}}
8132     # no errors
8133     # . epilogue
8134     89/<- %esp 5/r32/ebp
8135     5d/pop-to-ebp
8136     c3/return
8138 test-copy-non-literal-to-byte:
8139     # . prologue
8140     55/push-ebp
8141     89/<- %ebp 4/r32/esp
8142     # setup
8143     (clear-stream _test-input-stream)
8144     (clear-stream $_test-input-buffered-file->buffer)
8145     (clear-stream _test-output-stream)
8146     (clear-stream $_test-output-buffered-file->buffer)
8147     (clear-stream _test-error-stream)
8148     (clear-stream $_test-error-buffered-file->buffer)
8149     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
8150     68/push 0/imm32
8151     68/push 0/imm32
8152     89/<- %edx 4/r32/esp
8153     (tailor-exit-descriptor %edx 0x10)
8154     #
8155     (write _test-input-stream "fn foo {\n")
8156     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
8157     (write _test-input-stream "  var y/ecx: byte <- copy x\n")
8158     (write _test-input-stream "}\n")
8159     # convert
8160     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
8161     # registers except esp clobbered at this point
8162     # restore ed
8163     89/<- %edx 4/r32/esp
8164     (flush _test-output-buffered-file)
8165     (flush _test-error-buffered-file)
8166 #?     # dump _test-error-stream {{{
8167 #?     (write 2 "^")
8168 #?     (write-stream 2 _test-error-stream)
8169 #?     (write 2 "$\n")
8170 #?     (rewind-stream _test-error-stream)
8171 #?     # }}}
8172     # check output
8173     (check-stream-equal _test-output-stream  ""  "F - test-copy-non-literal-to-byte: output should be empty")
8174     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt copy: cannot copy non-literal to 'y' of type byte; use copy-byte"  "F - test-copy-non-literal-to-byte: error message")
8175     # check that stop(1) was called
8176     (check-ints-equal *(edx+4) 2 "F - test-copy-non-literal-to-byte: exit status")
8177     # don't restore from ebp
8178     81 0/subop/add %esp 8/imm32
8179     # . epilogue
8180     5d/pop-to-ebp
8181     c3/return
8183 test-copy-deref-address:
8184     # . prologue
8185     55/push-ebp
8186     89/<- %ebp 4/r32/esp
8187     # setup
8188     (clear-stream _test-input-stream)
8189     (clear-stream $_test-input-buffered-file->buffer)
8190     (clear-stream _test-output-stream)
8191     (clear-stream $_test-output-buffered-file->buffer)
8192     #
8193     (write _test-input-stream "fn foo {\n")
8194     (write _test-input-stream "  var x/eax: (addr addr int) <- copy 0\n")
8195     (write _test-input-stream "  var y/ecx: (addr int) <- copy *x\n")
8196     (write _test-input-stream "}\n")
8197     # convert
8198     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
8199     (flush _test-output-buffered-file)
8200     # no errors
8201     # . epilogue
8202     5d/pop-to-ebp
8203     c3/return
8205 test-copy-to-non-register:
8206     # . prologue
8207     55/push-ebp
8208     89/<- %ebp 4/r32/esp
8209     # setup
8210     (clear-stream _test-input-stream)
8211     (clear-stream $_test-input-buffered-file->buffer)
8212     (clear-stream _test-output-stream)
8213     (clear-stream $_test-output-buffered-file->buffer)
8214     (clear-stream _test-error-stream)
8215     (clear-stream $_test-error-buffered-file->buffer)
8216     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
8217     68/push 0/imm32
8218     68/push 0/imm32
8219     89/<- %edx 4/r32/esp
8220     (tailor-exit-descriptor %edx 0x10)
8221     #
8222     (write _test-input-stream "fn foo {\n")
8223     (write _test-input-stream "  var x: int\n")
8224     (write _test-input-stream "  x <- copy 0\n")
8225     (write _test-input-stream "}\n")
8226     # convert
8227     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
8228     # registers except esp clobbered at this point
8229     # restore ed
8230     89/<- %edx 4/r32/esp
8231     (flush _test-output-buffered-file)
8232     (flush _test-error-buffered-file)
8233 #?     # dump _test-error-stream {{{
8234 #?     (write 2 "^")
8235 #?     (write-stream 2 _test-error-stream)
8236 #?     (write 2 "$\n")
8237 #?     (rewind-stream _test-error-stream)
8238 #?     # }}}
8239     # check output
8240     (check-stream-equal _test-output-stream  ""  "F - test-copy-to-non-register: output should be empty")
8241     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt copy: output 'x' not in a register"  "F - test-copy-to-non-register: error message")
8242     # check that stop(1) was called
8243     (check-ints-equal *(edx+4) 2 "F - test-copy-to-non-register: exit status")
8244     # don't restore from ebp
8245     81 0/subop/add %esp 8/imm32
8246     # . epilogue
8247     5d/pop-to-ebp
8248     c3/return
8250 test-copy-from-non-scalar-inout:
8251     # . prologue
8252     55/push-ebp
8253     89/<- %ebp 4/r32/esp
8254     # setup
8255     (clear-stream _test-input-stream)
8256     (clear-stream $_test-input-buffered-file->buffer)
8257     (clear-stream _test-output-stream)
8258     (clear-stream $_test-output-buffered-file->buffer)
8259     (clear-stream _test-error-stream)
8260     (clear-stream $_test-error-buffered-file->buffer)
8261     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
8262     68/push 0/imm32
8263     68/push 0/imm32
8264     89/<- %edx 4/r32/esp
8265     (tailor-exit-descriptor %edx 0x10)
8266     #
8267     (write _test-input-stream "fn foo {\n")
8268     (write _test-input-stream "  var x: (handle int)\n")
8269     (write _test-input-stream "  var y/eax: int <- copy x\n")
8270     (write _test-input-stream "}\n")
8271     # convert
8272     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
8273     # registers except esp clobbered at this point
8274     # restore ed
8275     89/<- %edx 4/r32/esp
8276     (flush _test-output-buffered-file)
8277     (flush _test-error-buffered-file)
8278 #?     # dump _test-error-stream {{{
8279 #?     (write 2 "^")
8280 #?     (write-stream 2 _test-error-stream)
8281 #?     (write 2 "$\n")
8282 #?     (rewind-stream _test-error-stream)
8283 #?     # }}}
8284     # check output
8285     (check-stream-equal _test-output-stream  ""  "F - test-copy-from-non-scalar-inout: output should be empty")
8286     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt copy: 'x' is too large to fit in a register"  "F - test-copy-from-non-scalar-inout: error message")
8287     # check that stop(1) was called
8288     (check-ints-equal *(edx+4) 2 "F - test-copy-from-non-scalar-inout: exit status")
8289     # don't restore from ebp
8290     81 0/subop/add %esp 8/imm32
8291     # . epilogue
8292     5d/pop-to-ebp
8293     c3/return
8295 test-copy-to-with-no-inout:
8296     # . prologue
8297     55/push-ebp
8298     89/<- %ebp 4/r32/esp
8299     # setup
8300     (clear-stream _test-input-stream)
8301     (clear-stream $_test-input-buffered-file->buffer)
8302     (clear-stream _test-output-stream)
8303     (clear-stream $_test-output-buffered-file->buffer)
8304     (clear-stream _test-error-stream)
8305     (clear-stream $_test-error-buffered-file->buffer)
8306     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
8307     68/push 0/imm32
8308     68/push 0/imm32
8309     89/<- %edx 4/r32/esp
8310     (tailor-exit-descriptor %edx 0x10)
8311     #
8312     (write _test-input-stream "fn foo {\n")
8313     (write _test-input-stream "  copy-to\n")
8314     (write _test-input-stream "}\n")
8315     # convert
8316     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
8317     # registers except esp clobbered at this point
8318     # restore ed
8319     89/<- %edx 4/r32/esp
8320     (flush _test-output-buffered-file)
8321     (flush _test-error-buffered-file)
8322 #?     # dump _test-error-stream {{{
8323 #?     (write 2 "^")
8324 #?     (write-stream 2 _test-error-stream)
8325 #?     (write 2 "$\n")
8326 #?     (rewind-stream _test-error-stream)
8327 #?     # }}}
8328     # check output
8329     (check-stream-equal _test-output-stream  ""  "F - test-copy-to-with-no-inout: output should be empty")
8330     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'copy-to' must have two inouts"  "F - test-copy-to-with-no-inout: error message")
8331     # check that stop(1) was called
8332     (check-ints-equal *(edx+4) 2 "F - test-copy-to-with-no-inout: exit status")
8333     # don't restore from ebp
8334     81 0/subop/add %esp 8/imm32
8335     # . epilogue
8336     5d/pop-to-ebp
8337     c3/return
8339 test-copy-to-with-no-source:
8340     # . prologue
8341     55/push-ebp
8342     89/<- %ebp 4/r32/esp
8343     # setup
8344     (clear-stream _test-input-stream)
8345     (clear-stream $_test-input-buffered-file->buffer)
8346     (clear-stream _test-output-stream)
8347     (clear-stream $_test-output-buffered-file->buffer)
8348     (clear-stream _test-error-stream)
8349     (clear-stream $_test-error-buffered-file->buffer)
8350     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
8351     68/push 0/imm32
8352     68/push 0/imm32
8353     89/<- %edx 4/r32/esp
8354     (tailor-exit-descriptor %edx 0x10)
8355     #
8356     (write _test-input-stream "fn foo {\n")
8357     (write _test-input-stream "  var x: boolean\n")
8358     (write _test-input-stream "  copy-to x\n")
8359     (write _test-input-stream "}\n")
8360     # convert
8361     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
8362     # registers except esp clobbered at this point
8363     # restore ed
8364     89/<- %edx 4/r32/esp
8365     (flush _test-output-buffered-file)
8366     (flush _test-error-buffered-file)
8367 #?     # dump _test-error-stream {{{
8368 #?     (write 2 "^")
8369 #?     (write-stream 2 _test-error-stream)
8370 #?     (write 2 "$\n")
8371 #?     (rewind-stream _test-error-stream)
8372 #?     # }}}
8373     # check output
8374     (check-stream-equal _test-output-stream  ""  "F - test-copy-to-with-no-source: output should be empty")
8375     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'copy-to' must have two inouts"  "F - test-copy-to-with-no-source: error message")
8376     # check that stop(1) was called
8377     (check-ints-equal *(edx+4) 2 "F - test-copy-to-with-no-source: exit status")
8378     # don't restore from ebp
8379     81 0/subop/add %esp 8/imm32
8380     # . epilogue
8381     5d/pop-to-ebp
8382     c3/return
8384 test-copy-to-with-no-register:
8385     # . prologue
8386     55/push-ebp
8387     89/<- %ebp 4/r32/esp
8388     # setup
8389     (clear-stream _test-input-stream)
8390     (clear-stream $_test-input-buffered-file->buffer)
8391     (clear-stream _test-output-stream)
8392     (clear-stream $_test-output-buffered-file->buffer)
8393     (clear-stream _test-error-stream)
8394     (clear-stream $_test-error-buffered-file->buffer)
8395     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
8396     68/push 0/imm32
8397     68/push 0/imm32
8398     89/<- %edx 4/r32/esp
8399     (tailor-exit-descriptor %edx 0x10)
8400     #
8401     (write _test-input-stream "fn foo {\n")
8402     (write _test-input-stream "  var x: boolean\n")
8403     (write _test-input-stream "  copy-to x, x\n")
8404     (write _test-input-stream "}\n")
8405     # convert
8406     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
8407     # registers except esp clobbered at this point
8408     # restore ed
8409     89/<- %edx 4/r32/esp
8410     (flush _test-output-buffered-file)
8411     (flush _test-error-buffered-file)
8412 #?     # dump _test-error-stream {{{
8413 #?     (write 2 "^")
8414 #?     (write-stream 2 _test-error-stream)
8415 #?     (write 2 "$\n")
8416 #?     (rewind-stream _test-error-stream)
8417 #?     # }}}
8418     # check output
8419     (check-stream-equal _test-output-stream  ""  "F - test-copy-to-with-no-register: output should be empty")
8420     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt copy-to: source (second inout) is in memory"  "F - test-copy-to-with-no-register: error message")
8421     # check that stop(1) was called
8422     (check-ints-equal *(edx+4) 2 "F - test-copy-to-with-no-register: exit status")
8423     # don't restore from ebp
8424     81 0/subop/add %esp 8/imm32
8425     # . epilogue
8426     5d/pop-to-ebp
8427     c3/return
8429 test-copy-to-with-too-many-inouts:
8430     # . prologue
8431     55/push-ebp
8432     89/<- %ebp 4/r32/esp
8433     # setup
8434     (clear-stream _test-input-stream)
8435     (clear-stream $_test-input-buffered-file->buffer)
8436     (clear-stream _test-output-stream)
8437     (clear-stream $_test-output-buffered-file->buffer)
8438     (clear-stream _test-error-stream)
8439     (clear-stream $_test-error-buffered-file->buffer)
8440     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
8441     68/push 0/imm32
8442     68/push 0/imm32
8443     89/<- %edx 4/r32/esp
8444     (tailor-exit-descriptor %edx 0x10)
8445     #
8446     (write _test-input-stream "fn foo {\n")
8447     (write _test-input-stream "  var x: boolean\n")
8448     (write _test-input-stream "  copy-to x, 0, 0\n")
8449     (write _test-input-stream "}\n")
8450     # convert
8451     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
8452     # registers except esp clobbered at this point
8453     # restore ed
8454     89/<- %edx 4/r32/esp
8455     (flush _test-output-buffered-file)
8456     (flush _test-error-buffered-file)
8457 #?     # dump _test-error-stream {{{
8458 #?     (write 2 "^")
8459 #?     (write-stream 2 _test-error-stream)
8460 #?     (write 2 "$\n")
8461 #?     (rewind-stream _test-error-stream)
8462 #?     # }}}
8463     # check output
8464     (check-stream-equal _test-output-stream  ""  "F - test-copy-to-with-too-many-inouts: output should be empty")
8465     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'copy-to' must have two inouts"  "F - test-copy-to-with-too-many-inouts: error message")
8466     # check that stop(1) was called
8467     (check-ints-equal *(edx+4) 2 "F - test-copy-to-with-too-many-inouts: exit status")
8468     # don't restore from ebp
8469     81 0/subop/add %esp 8/imm32
8470     # . epilogue
8471     5d/pop-to-ebp
8472     c3/return
8474 test-copy-to-with-output:
8475     # . prologue
8476     55/push-ebp
8477     89/<- %ebp 4/r32/esp
8478     # setup
8479     (clear-stream _test-input-stream)
8480     (clear-stream $_test-input-buffered-file->buffer)
8481     (clear-stream _test-output-stream)
8482     (clear-stream $_test-output-buffered-file->buffer)
8483     (clear-stream _test-error-stream)
8484     (clear-stream $_test-error-buffered-file->buffer)
8485     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
8486     68/push 0/imm32
8487     68/push 0/imm32
8488     89/<- %edx 4/r32/esp
8489     (tailor-exit-descriptor %edx 0x10)
8490     #
8491     (write _test-input-stream "fn foo {\n")
8492     (write _test-input-stream "  var x/eax: boolean <- copy 0\n")
8493     (write _test-input-stream "  var y/ecx: boolean <- copy 0\n")
8494     (write _test-input-stream "  x <- copy-to y, 0\n")
8495     (write _test-input-stream "}\n")
8496     # convert
8497     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
8498     # registers except esp clobbered at this point
8499     # restore ed
8500     89/<- %edx 4/r32/esp
8501     (flush _test-output-buffered-file)
8502     (flush _test-error-buffered-file)
8503 #?     # dump _test-error-stream {{{
8504 #?     (write 2 "^")
8505 #?     (write-stream 2 _test-error-stream)
8506 #?     (write 2 "$\n")
8507 #?     (rewind-stream _test-error-stream)
8508 #?     # }}}
8509     # check output
8510     (check-stream-equal _test-output-stream  ""  "F - test-copy-to-with-output: output should be empty")
8511     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'copy-to' must not have any outputs"  "F - test-copy-to-with-output: error message")
8512     # check that stop(1) was called
8513     (check-ints-equal *(edx+4) 2 "F - test-copy-to-with-output: exit status")
8514     # don't restore from ebp
8515     81 0/subop/add %esp 8/imm32
8516     # . epilogue
8517     5d/pop-to-ebp
8518     c3/return
8520 test-copy-to-invalid-value-to-address:
8521     # . prologue
8522     55/push-ebp
8523     89/<- %ebp 4/r32/esp
8524     # setup
8525     (clear-stream _test-input-stream)
8526     (clear-stream $_test-input-buffered-file->buffer)
8527     (clear-stream _test-output-stream)
8528     (clear-stream $_test-output-buffered-file->buffer)
8529     (clear-stream _test-error-stream)
8530     (clear-stream $_test-error-buffered-file->buffer)
8531     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
8532     68/push 0/imm32
8533     68/push 0/imm32
8534     89/<- %edx 4/r32/esp
8535     (tailor-exit-descriptor %edx 0x10)
8536     #
8537     (write _test-input-stream "fn foo {\n")
8538     (write _test-input-stream "  var x/eax: int <- copy 0\n")
8539     (write _test-input-stream "  var y: (addr int)\n")
8540     (write _test-input-stream "  copy-to y, x\n")
8541     (write _test-input-stream "}\n")
8542     # convert
8543     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
8544     # registers except esp clobbered at this point
8545     # restore ed
8546     89/<- %edx 4/r32/esp
8547     (flush _test-output-buffered-file)
8548     (flush _test-error-buffered-file)
8549 #?     # dump _test-error-stream {{{
8550 #?     (write 2 "^")
8551 #?     (write-stream 2 _test-error-stream)
8552 #?     (write 2 "$\n")
8553 #?     (rewind-stream _test-error-stream)
8554 #?     # }}}
8555     # check output
8556     (check-stream-equal _test-output-stream  ""  "F - test-copy-to-invalid-value-to-address: output should be empty")
8557     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt copy-to: 'y' must be a non-addr non-offset scalar"  "F - test-copy-to-invalid-value-to-address: error message")
8558     # check that stop(1) was called
8559     (check-ints-equal *(edx+4) 2 "F - test-copy-to-invalid-value-to-address: exit status")
8560     # don't restore from ebp
8561     81 0/subop/add %esp 8/imm32
8562     # . epilogue
8563     5d/pop-to-ebp
8564     c3/return
8566 test-copy-to-null-value-to-address:
8567     # . prologue
8568     55/push-ebp
8569     89/<- %ebp 4/r32/esp
8570     # setup
8571     (clear-stream _test-input-stream)
8572     (clear-stream $_test-input-buffered-file->buffer)
8573     (clear-stream _test-output-stream)
8574     (clear-stream $_test-output-buffered-file->buffer)
8575     #
8576     (write _test-input-stream "fn foo {\n")
8577     (write _test-input-stream "  var y: (addr int)\n")
8578     (write _test-input-stream "  copy-to y, 0\n")
8579     (write _test-input-stream "}\n")
8580     # convert
8581     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
8582     (flush _test-output-buffered-file)
8583     # no errors
8584     # . epilogue
8585     89/<- %esp 5/r32/ebp
8586     5d/pop-to-ebp
8587     c3/return
8589 test-copy-to-invalid-value-to-offset:
8590     # . prologue
8591     55/push-ebp
8592     89/<- %ebp 4/r32/esp
8593     # setup
8594     (clear-stream _test-input-stream)
8595     (clear-stream $_test-input-buffered-file->buffer)
8596     (clear-stream _test-output-stream)
8597     (clear-stream $_test-output-buffered-file->buffer)
8598     (clear-stream _test-error-stream)
8599     (clear-stream $_test-error-buffered-file->buffer)
8600     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
8601     68/push 0/imm32
8602     68/push 0/imm32
8603     89/<- %edx 4/r32/esp
8604     (tailor-exit-descriptor %edx 0x10)
8605     #
8606     (write _test-input-stream "fn foo {\n")
8607     (write _test-input-stream "  var x/eax: int <- copy 0\n")
8608     (write _test-input-stream "  var y: (offset int)\n")
8609     (write _test-input-stream "  copy-to y, x\n")
8610     (write _test-input-stream "}\n")
8611     # convert
8612     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
8613     # registers except esp clobbered at this point
8614     # restore ed
8615     89/<- %edx 4/r32/esp
8616     (flush _test-output-buffered-file)
8617     (flush _test-error-buffered-file)
8618 #?     # dump _test-error-stream {{{
8619 #?     (write 2 "^")
8620 #?     (write-stream 2 _test-error-stream)
8621 #?     (write 2 "$\n")
8622 #?     (rewind-stream _test-error-stream)
8623 #?     # }}}
8624     # check output
8625     (check-stream-equal _test-output-stream  ""  "F - test-copy-to-invalid-value-to-offset: output should be empty")
8626     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt copy-to: 'y' must be a non-addr non-offset scalar"  "F - test-copy-to-invalid-value-to-offset: error message")
8627     # check that stop(1) was called
8628     (check-ints-equal *(edx+4) 2 "F - test-copy-to-invalid-value-to-offset: exit status")
8629     # don't restore from ebp
8630     81 0/subop/add %esp 8/imm32
8631     # . epilogue
8632     5d/pop-to-ebp
8633     c3/return
8635 test-copy-to-null-value-to-offset:
8636     # . prologue
8637     55/push-ebp
8638     89/<- %ebp 4/r32/esp
8639     # setup
8640     (clear-stream _test-input-stream)
8641     (clear-stream $_test-input-buffered-file->buffer)
8642     (clear-stream _test-output-stream)
8643     (clear-stream $_test-output-buffered-file->buffer)
8644     #
8645     (write _test-input-stream "fn foo {\n")
8646     (write _test-input-stream "  var y: (offset int)\n")
8647     (write _test-input-stream "  copy-to y, 0\n")
8648     (write _test-input-stream "}\n")
8649     # convert
8650     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
8651     (flush _test-output-buffered-file)
8652     # no errors
8653     # . epilogue
8654     89/<- %esp 5/r32/ebp
8655     5d/pop-to-ebp
8656     c3/return
8658 test-copy-to-non-literal-to-byte:
8659     # . prologue
8660     55/push-ebp
8661     89/<- %ebp 4/r32/esp
8662     # setup
8663     (clear-stream _test-input-stream)
8664     (clear-stream $_test-input-buffered-file->buffer)
8665     (clear-stream _test-output-stream)
8666     (clear-stream $_test-output-buffered-file->buffer)
8667     (clear-stream _test-error-stream)
8668     (clear-stream $_test-error-buffered-file->buffer)
8669     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
8670     68/push 0/imm32
8671     68/push 0/imm32
8672     89/<- %edx 4/r32/esp
8673     (tailor-exit-descriptor %edx 0x10)
8674     #
8675     (write _test-input-stream "fn foo {\n")
8676     (write _test-input-stream "  var x/ecx: byte <- copy 3\n")
8677     (write _test-input-stream "  var y/eax: (addr byte) <- copy 0\n")
8678     (write _test-input-stream "  copy-to *y, x\n")
8679     (write _test-input-stream "}\n")
8680     # convert
8681     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
8682     # registers except esp clobbered at this point
8683     # restore ed
8684     89/<- %edx 4/r32/esp
8685     (flush _test-output-buffered-file)
8686     (flush _test-error-buffered-file)
8687 #?     # dump _test-error-stream {{{
8688 #?     (write 2 "^")
8689 #?     (write-stream 2 _test-error-stream)
8690 #?     (write 2 "$\n")
8691 #?     (rewind-stream _test-error-stream)
8692 #?     # }}}
8693     # check output
8694     (check-stream-equal _test-output-stream  ""  "F - test-copy-to-non-literal-to-byte: output should be empty")
8695     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt copy-to: cannot copy non-literal to type byte; use copy-byte-to"  "F - test-copy-to-non-literal-to-byte: error message")
8696     # check that stop(1) was called
8697     (check-ints-equal *(edx+4) 2 "F - test-copy-to-non-literal-to-byte: exit status")
8698     # don't restore from ebp
8699     81 0/subop/add %esp 8/imm32
8700     # . epilogue
8701     5d/pop-to-ebp
8702     c3/return
8704 test-copy-to-deref-address:
8705     # . prologue
8706     55/push-ebp
8707     89/<- %ebp 4/r32/esp
8708     # setup
8709     (clear-stream _test-input-stream)
8710     (clear-stream $_test-input-buffered-file->buffer)
8711     (clear-stream _test-output-stream)
8712     (clear-stream $_test-output-buffered-file->buffer)
8713     #
8714     (write _test-input-stream "fn foo {\n")
8715     (write _test-input-stream "  var x/eax: (addr int) <- copy 0\n")
8716     (write _test-input-stream "  var y/ecx: (addr addr int) <- copy 0\n")
8717     (write _test-input-stream "  copy-to *y, x\n")
8718     (write _test-input-stream "}\n")
8719     # convert
8720     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
8721     (flush _test-output-buffered-file)
8722     # no errors
8723     # . epilogue
8724     5d/pop-to-ebp
8725     c3/return
8727 test-copy-to-from-non-scalar-inout:
8728     # . prologue
8729     55/push-ebp
8730     89/<- %ebp 4/r32/esp
8731     # setup
8732     (clear-stream _test-input-stream)
8733     (clear-stream $_test-input-buffered-file->buffer)
8734     (clear-stream _test-output-stream)
8735     (clear-stream $_test-output-buffered-file->buffer)
8736     (clear-stream _test-error-stream)
8737     (clear-stream $_test-error-buffered-file->buffer)
8738     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
8739     68/push 0/imm32
8740     68/push 0/imm32
8741     89/<- %edx 4/r32/esp
8742     (tailor-exit-descriptor %edx 0x10)
8743     #
8744     (write _test-input-stream "fn foo {\n")
8745     (write _test-input-stream "  var x: (handle int)\n")
8746     (write _test-input-stream "  var y: int\n")
8747     (write _test-input-stream "  copy-to y, x\n")
8748     (write _test-input-stream "}\n")
8749     # convert
8750     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
8751     # registers except esp clobbered at this point
8752     # restore ed
8753     89/<- %edx 4/r32/esp
8754     (flush _test-output-buffered-file)
8755     (flush _test-error-buffered-file)
8756 #?     # dump _test-error-stream {{{
8757 #?     (write 2 "^")
8758 #?     (write-stream 2 _test-error-stream)
8759 #?     (write 2 "$\n")
8760 #?     (rewind-stream _test-error-stream)
8761 #?     # }}}
8762     # check output
8763     (check-stream-equal _test-output-stream  ""  "F - test-copy-to-from-non-scalar-inout: output should be empty")
8764     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt copy-to: 'x' is too large to copy"  "F - test-copy-to-from-non-scalar-inout: error message")
8765     # check that stop(1) was called
8766     (check-ints-equal *(edx+4) 2 "F - test-copy-to-from-non-scalar-inout: exit status")
8767     # don't restore from ebp
8768     81 0/subop/add %esp 8/imm32
8769     # . epilogue
8770     5d/pop-to-ebp
8771     c3/return
8773 test-copy-byte-with-no-inout:
8774     # . prologue
8775     55/push-ebp
8776     89/<- %ebp 4/r32/esp
8777     # setup
8778     (clear-stream _test-input-stream)
8779     (clear-stream $_test-input-buffered-file->buffer)
8780     (clear-stream _test-output-stream)
8781     (clear-stream $_test-output-buffered-file->buffer)
8782     (clear-stream _test-error-stream)
8783     (clear-stream $_test-error-buffered-file->buffer)
8784     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
8785     68/push 0/imm32
8786     68/push 0/imm32
8787     89/<- %edx 4/r32/esp
8788     (tailor-exit-descriptor %edx 0x10)
8789     #
8790     (write _test-input-stream "fn foo {\n")
8791     (write _test-input-stream "  var x/eax: byte <- copy-byte\n")
8792     (write _test-input-stream "}\n")
8793     # convert
8794     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
8795     # registers except esp clobbered at this point
8796     # restore ed
8797     89/<- %edx 4/r32/esp
8798     (flush _test-output-buffered-file)
8799     (flush _test-error-buffered-file)
8800 #?     # dump _test-error-stream {{{
8801 #?     (write 2 "^")
8802 #?     (write-stream 2 _test-error-stream)
8803 #?     (write 2 "$\n")
8804 #?     (rewind-stream _test-error-stream)
8805 #?     # }}}
8806     # check output
8807     (check-stream-equal _test-output-stream  ""  "F - test-copy-byte-with-no-inout: output should be empty")
8808     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'copy-byte' expects an inout"  "F - test-copy-byte-with-no-inout: error message")
8809     # check that stop(1) was called
8810     (check-ints-equal *(edx+4) 2 "F - test-copy-byte-with-no-inout: exit status")
8811     # don't restore from ebp
8812     81 0/subop/add %esp 8/imm32
8813     # . epilogue
8814     5d/pop-to-ebp
8815     c3/return
8817 test-copy-byte-with-multiple-inouts:
8818     # . prologue
8819     55/push-ebp
8820     89/<- %ebp 4/r32/esp
8821     # setup
8822     (clear-stream _test-input-stream)
8823     (clear-stream $_test-input-buffered-file->buffer)
8824     (clear-stream _test-output-stream)
8825     (clear-stream $_test-output-buffered-file->buffer)
8826     (clear-stream _test-error-stream)
8827     (clear-stream $_test-error-buffered-file->buffer)
8828     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
8829     68/push 0/imm32
8830     68/push 0/imm32
8831     89/<- %edx 4/r32/esp
8832     (tailor-exit-descriptor %edx 0x10)
8833     #
8834     (write _test-input-stream "fn foo {\n")
8835     (write _test-input-stream "  var x/eax: byte <- copy-byte 0, 0\n")
8836     (write _test-input-stream "}\n")
8837     # convert
8838     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
8839     # registers except esp clobbered at this point
8840     # restore ed
8841     89/<- %edx 4/r32/esp
8842     (flush _test-output-buffered-file)
8843     (flush _test-error-buffered-file)
8844 #?     # dump _test-error-stream {{{
8845 #?     (write 2 "^")
8846 #?     (write-stream 2 _test-error-stream)
8847 #?     (write 2 "$\n")
8848 #?     (rewind-stream _test-error-stream)
8849 #?     # }}}
8850     # check output
8851     (check-stream-equal _test-output-stream  ""  "F - test-copy-byte-with-multiple-inouts: output should be empty")
8852     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'copy-byte' must have just one inout"  "F - test-copy-byte-with-multiple-inouts: error message")
8853     # check that stop(1) was called
8854     (check-ints-equal *(edx+4) 2 "F - test-copy-byte-with-multiple-inouts: exit status")
8855     # don't restore from ebp
8856     81 0/subop/add %esp 8/imm32
8857     # . epilogue
8858     5d/pop-to-ebp
8859     c3/return
8861 test-copy-byte-with-no-output:
8862     # . prologue
8863     55/push-ebp
8864     89/<- %ebp 4/r32/esp
8865     # setup
8866     (clear-stream _test-input-stream)
8867     (clear-stream $_test-input-buffered-file->buffer)
8868     (clear-stream _test-output-stream)
8869     (clear-stream $_test-output-buffered-file->buffer)
8870     (clear-stream _test-error-stream)
8871     (clear-stream $_test-error-buffered-file->buffer)
8872     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
8873     68/push 0/imm32
8874     68/push 0/imm32
8875     89/<- %edx 4/r32/esp
8876     (tailor-exit-descriptor %edx 0x10)
8877     #
8878     (write _test-input-stream "fn foo {\n")
8879     (write _test-input-stream "  copy-byte 0\n")
8880     (write _test-input-stream "}\n")
8881     # convert
8882     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
8883     # registers except esp clobbered at this point
8884     # restore ed
8885     89/<- %edx 4/r32/esp
8886     (flush _test-output-buffered-file)
8887     (flush _test-error-buffered-file)
8888 #?     # dump _test-error-stream {{{
8889 #?     (write 2 "^")
8890 #?     (write-stream 2 _test-error-stream)
8891 #?     (write 2 "$\n")
8892 #?     (rewind-stream _test-error-stream)
8893 #?     # }}}
8894     # check output
8895     (check-stream-equal _test-output-stream  ""  "F - test-copy-byte-with-no-output: output should be empty")
8896     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'copy-byte' expects an output"  "F - test-copy-byte-with-no-output: error message")
8897     # check that stop(1) was called
8898     (check-ints-equal *(edx+4) 2 "F - test-copy-byte-with-no-output: exit status")
8899     # don't restore from ebp
8900     81 0/subop/add %esp 8/imm32
8901     # . epilogue
8902     5d/pop-to-ebp
8903     c3/return
8905 test-copy-byte-with-multiple-outputs:
8906     # . prologue
8907     55/push-ebp
8908     89/<- %ebp 4/r32/esp
8909     # setup
8910     (clear-stream _test-input-stream)
8911     (clear-stream $_test-input-buffered-file->buffer)
8912     (clear-stream _test-output-stream)
8913     (clear-stream $_test-output-buffered-file->buffer)
8914     (clear-stream _test-error-stream)
8915     (clear-stream $_test-error-buffered-file->buffer)
8916     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
8917     68/push 0/imm32
8918     68/push 0/imm32
8919     89/<- %edx 4/r32/esp
8920     (tailor-exit-descriptor %edx 0x10)
8921     #
8922     (write _test-input-stream "fn foo {\n")
8923     (write _test-input-stream "  var x/eax: byte <- copy 0\n")
8924     (write _test-input-stream "  var y/ecx: byte <- copy 0\n")
8925     (write _test-input-stream "  x, y <- copy-byte 0\n")
8926     (write _test-input-stream "}\n")
8927     # convert
8928     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
8929     # registers except esp clobbered at this point
8930     # restore ed
8931     89/<- %edx 4/r32/esp
8932     (flush _test-output-buffered-file)
8933     (flush _test-error-buffered-file)
8934 #?     # dump _test-error-stream {{{
8935 #?     (write 2 "^")
8936 #?     (write-stream 2 _test-error-stream)
8937 #?     (write 2 "$\n")
8938 #?     (rewind-stream _test-error-stream)
8939 #?     # }}}
8940     # check output
8941     (check-stream-equal _test-output-stream  ""  "F - test-copy-byte-with-multiple-outputs: output should be empty")
8942     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'copy-byte' must have just one output"  "F - test-copy-byte-with-multiple-outputs: error message")
8943     # check that stop(1) was called
8944     (check-ints-equal *(edx+4) 2 "F - test-copy-byte-with-multiple-outputs: exit status")
8945     # don't restore from ebp
8946     81 0/subop/add %esp 8/imm32
8947     # . epilogue
8948     5d/pop-to-ebp
8949     c3/return
8951 test-copy-byte-deref-address:
8952     # . prologue
8953     55/push-ebp
8954     89/<- %ebp 4/r32/esp
8955     # setup
8956     (clear-stream _test-input-stream)
8957     (clear-stream $_test-input-buffered-file->buffer)
8958     (clear-stream _test-output-stream)
8959     (clear-stream $_test-output-buffered-file->buffer)
8960     #
8961     (write _test-input-stream "fn foo {\n")
8962     (write _test-input-stream "  var x/eax: (addr byte) <- copy 0\n")
8963     (write _test-input-stream "  var y/ecx: byte <- copy-byte *x\n")
8964     (write _test-input-stream "}\n")
8965     # convert
8966     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
8967     (flush _test-output-buffered-file)
8968 #?     # dump _test-error-stream {{{
8969 #?     (write 2 "^")
8970 #?     (write-stream 2 _test-error-stream)
8971 #?     (write 2 "$\n")
8972 #?     (rewind-stream _test-error-stream)
8973 #?     # }}}
8974     # not bothering checking output
8975     (check-next-stream-line-equal _test-error-stream  ""  "F - test-copy-byte-deref-address: error message")
8976     # . epilogue
8977     5d/pop-to-ebp
8978     c3/return
8980 test-copy-byte-with-invalid-output-type:
8981     # . prologue
8982     55/push-ebp
8983     89/<- %ebp 4/r32/esp
8984     # setup
8985     (clear-stream _test-input-stream)
8986     (clear-stream $_test-input-buffered-file->buffer)
8987     (clear-stream _test-output-stream)
8988     (clear-stream $_test-output-buffered-file->buffer)
8989     (clear-stream _test-error-stream)
8990     (clear-stream $_test-error-buffered-file->buffer)
8991     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
8992     68/push 0/imm32
8993     68/push 0/imm32
8994     89/<- %edx 4/r32/esp
8995     (tailor-exit-descriptor %edx 0x10)
8996     #
8997     (write _test-input-stream "fn foo {\n")
8998     (write _test-input-stream "  var x/eax: (addr byte) <- copy 0\n")
8999     (write _test-input-stream "  var y/eax: int <- copy-byte *x\n")
9000     (write _test-input-stream "}\n")
9001     # convert
9002     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
9003     # registers except esp clobbered at this point
9004     # restore ed
9005     89/<- %edx 4/r32/esp
9006     (flush _test-output-buffered-file)
9007     (flush _test-error-buffered-file)
9008 #?     # dump _test-error-stream {{{
9009 #?     (write 2 "^")
9010 #?     (write-stream 2 _test-error-stream)
9011 #?     (write 2 "$\n")
9012 #?     (rewind-stream _test-error-stream)
9013 #?     # }}}
9014     # check output
9015     (check-stream-equal _test-output-stream  ""  "F - test-copy-byte-with-invalid-output-type: output should be empty")
9016     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'copy-byte' must write to output of type byte"  "F - test-copy-byte-with-invalid-output-type: error message")
9017     # check that stop(1) was called
9018     (check-ints-equal *(edx+4) 2 "F - test-copy-byte-with-invalid-output-type: exit status")
9019     # don't restore from ebp
9020     81 0/subop/add %esp 8/imm32
9021     # . epilogue
9022     5d/pop-to-ebp
9023     c3/return
9025 test-copy-byte-from-non-scalar-inout:
9026     # . prologue
9027     55/push-ebp
9028     89/<- %ebp 4/r32/esp
9029     # setup
9030     (clear-stream _test-input-stream)
9031     (clear-stream $_test-input-buffered-file->buffer)
9032     (clear-stream _test-output-stream)
9033     (clear-stream $_test-output-buffered-file->buffer)
9034     (clear-stream _test-error-stream)
9035     (clear-stream $_test-error-buffered-file->buffer)
9036     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
9037     68/push 0/imm32
9038     68/push 0/imm32
9039     89/<- %edx 4/r32/esp
9040     (tailor-exit-descriptor %edx 0x10)
9041     #
9042     (write _test-input-stream "fn foo {\n")
9043     (write _test-input-stream "  var x: (handle int)\n")
9044     (write _test-input-stream "  var y/eax: byte <- copy-byte x\n")
9045     (write _test-input-stream "}\n")
9046     # convert
9047     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
9048     # registers except esp clobbered at this point
9049     # restore ed
9050     89/<- %edx 4/r32/esp
9051     (flush _test-output-buffered-file)
9052     (flush _test-error-buffered-file)
9053 #?     # dump _test-error-stream {{{
9054 #?     (write 2 "^")
9055 #?     (write-stream 2 _test-error-stream)
9056 #?     (write 2 "$\n")
9057 #?     (rewind-stream _test-error-stream)
9058 #?     # }}}
9059     # check output
9060     (check-stream-equal _test-output-stream  ""  "F - test-copy-byte-from-non-scalar-inout: output should be empty")
9061     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt copy-byte: 'x' is too large to fit in a register"  "F - test-copy-byte-from-non-scalar-inout: error message")
9062     # check that stop(1) was called
9063     (check-ints-equal *(edx+4) 2 "F - test-copy-byte-from-non-scalar-inout: exit status")
9064     # don't restore from ebp
9065     81 0/subop/add %esp 8/imm32
9066     # . epilogue
9067     5d/pop-to-ebp
9068     c3/return
9070 test-copy-byte-to-with-no-inout:
9071     # . prologue
9072     55/push-ebp
9073     89/<- %ebp 4/r32/esp
9074     # setup
9075     (clear-stream _test-input-stream)
9076     (clear-stream $_test-input-buffered-file->buffer)
9077     (clear-stream _test-output-stream)
9078     (clear-stream $_test-output-buffered-file->buffer)
9079     (clear-stream _test-error-stream)
9080     (clear-stream $_test-error-buffered-file->buffer)
9081     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
9082     68/push 0/imm32
9083     68/push 0/imm32
9084     89/<- %edx 4/r32/esp
9085     (tailor-exit-descriptor %edx 0x10)
9086     #
9087     (write _test-input-stream "fn foo {\n")
9088     (write _test-input-stream "  copy-byte-to\n")
9089     (write _test-input-stream "}\n")
9090     # convert
9091     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
9092     # registers except esp clobbered at this point
9093     # restore ed
9094     89/<- %edx 4/r32/esp
9095     (flush _test-output-buffered-file)
9096     (flush _test-error-buffered-file)
9097 #?     # dump _test-error-stream {{{
9098 #?     (write 2 "^")
9099 #?     (write-stream 2 _test-error-stream)
9100 #?     (write 2 "$\n")
9101 #?     (rewind-stream _test-error-stream)
9102 #?     # }}}
9103     # check output
9104     (check-stream-equal _test-output-stream  ""  "F - test-copy-byte-to-with-no-inout: output should be empty")
9105     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'copy-byte-to' must have two inouts"  "F - test-copy-byte-to-with-no-inout: error message")
9106     # check that stop(1) was called
9107     (check-ints-equal *(edx+4) 2 "F - test-copy-byte-to-with-no-inout: exit status")
9108     # don't restore from ebp
9109     81 0/subop/add %esp 8/imm32
9110     # . epilogue
9111     5d/pop-to-ebp
9112     c3/return
9114 test-copy-byte-to-with-no-source:
9115     # . prologue
9116     55/push-ebp
9117     89/<- %ebp 4/r32/esp
9118     # setup
9119     (clear-stream _test-input-stream)
9120     (clear-stream $_test-input-buffered-file->buffer)
9121     (clear-stream _test-output-stream)
9122     (clear-stream $_test-output-buffered-file->buffer)
9123     (clear-stream _test-error-stream)
9124     (clear-stream $_test-error-buffered-file->buffer)
9125     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
9126     68/push 0/imm32
9127     68/push 0/imm32
9128     89/<- %edx 4/r32/esp
9129     (tailor-exit-descriptor %edx 0x10)
9130     #
9131     (write _test-input-stream "fn foo {\n")
9132     (write _test-input-stream "  var x/eax: (addr byte) <- copy 0\n")
9133     (write _test-input-stream "  copy-byte-to *x\n")
9134     (write _test-input-stream "}\n")
9135     # convert
9136     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
9137     # registers except esp clobbered at this point
9138     # restore ed
9139     89/<- %edx 4/r32/esp
9140     (flush _test-output-buffered-file)
9141     (flush _test-error-buffered-file)
9142 #?     # dump _test-error-stream {{{
9143 #?     (write 2 "^")
9144 #?     (write-stream 2 _test-error-stream)
9145 #?     (write 2 "$\n")
9146 #?     (rewind-stream _test-error-stream)
9147 #?     # }}}
9148     # check output
9149     (check-stream-equal _test-output-stream  ""  "F - test-copy-byte-to-with-no-source: output should be empty")
9150     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'copy-byte-to' must have two inouts"  "F - test-copy-byte-to-with-no-source: error message")
9151     # check that stop(1) was called
9152     (check-ints-equal *(edx+4) 2 "F - test-copy-byte-to-with-no-source: exit status")
9153     # don't restore from ebp
9154     81 0/subop/add %esp 8/imm32
9155     # . epilogue
9156     5d/pop-to-ebp
9157     c3/return
9159 test-copy-byte-to-with-too-many-inouts:
9160     # . prologue
9161     55/push-ebp
9162     89/<- %ebp 4/r32/esp
9163     # setup
9164     (clear-stream _test-input-stream)
9165     (clear-stream $_test-input-buffered-file->buffer)
9166     (clear-stream _test-output-stream)
9167     (clear-stream $_test-output-buffered-file->buffer)
9168     (clear-stream _test-error-stream)
9169     (clear-stream $_test-error-buffered-file->buffer)
9170     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
9171     68/push 0/imm32
9172     68/push 0/imm32
9173     89/<- %edx 4/r32/esp
9174     (tailor-exit-descriptor %edx 0x10)
9175     #
9176     (write _test-input-stream "fn foo {\n")
9177     (write _test-input-stream "  var x/eax: (addr byte) <- copy 0\n")
9178     (write _test-input-stream "  copy-byte-to *x, 0, 0\n")
9179     (write _test-input-stream "}\n")
9180     # convert
9181     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
9182     # registers except esp clobbered at this point
9183     # restore ed
9184     89/<- %edx 4/r32/esp
9185     (flush _test-output-buffered-file)
9186     (flush _test-error-buffered-file)
9187 #?     # dump _test-error-stream {{{
9188 #?     (write 2 "^")
9189 #?     (write-stream 2 _test-error-stream)
9190 #?     (write 2 "$\n")
9191 #?     (rewind-stream _test-error-stream)
9192 #?     # }}}
9193     # check output
9194     (check-stream-equal _test-output-stream  ""  "F - test-copy-byte-to-with-too-many-inouts: output should be empty")
9195     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'copy-byte-to' must have two inouts"  "F - test-copy-byte-to-with-too-many-inouts: error message")
9196     # check that stop(1) was called
9197     (check-ints-equal *(edx+4) 2 "F - test-copy-byte-to-with-too-many-inouts: exit status")
9198     # don't restore from ebp
9199     81 0/subop/add %esp 8/imm32
9200     # . epilogue
9201     5d/pop-to-ebp
9202     c3/return
9204 test-copy-byte-to-with-output:
9205     # . prologue
9206     55/push-ebp
9207     89/<- %ebp 4/r32/esp
9208     # setup
9209     (clear-stream _test-input-stream)
9210     (clear-stream $_test-input-buffered-file->buffer)
9211     (clear-stream _test-output-stream)
9212     (clear-stream $_test-output-buffered-file->buffer)
9213     (clear-stream _test-error-stream)
9214     (clear-stream $_test-error-buffered-file->buffer)
9215     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
9216     68/push 0/imm32
9217     68/push 0/imm32
9218     89/<- %edx 4/r32/esp
9219     (tailor-exit-descriptor %edx 0x10)
9220     #
9221     (write _test-input-stream "fn foo {\n")
9222     (write _test-input-stream "  var x/eax: byte <- copy 0\n")
9223     (write _test-input-stream "  var y/ecx: (addr byte) <- copy 0\n")
9224     (write _test-input-stream "  x <- copy-byte-to *y, 0\n")
9225     (write _test-input-stream "}\n")
9226     # convert
9227     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
9228     # registers except esp clobbered at this point
9229     # restore ed
9230     89/<- %edx 4/r32/esp
9231     (flush _test-output-buffered-file)
9232     (flush _test-error-buffered-file)
9233 #?     # dump _test-error-stream {{{
9234 #?     (write 2 "^")
9235 #?     (write-stream 2 _test-error-stream)
9236 #?     (write 2 "$\n")
9237 #?     (rewind-stream _test-error-stream)
9238 #?     # }}}
9239     # check output
9240     (check-stream-equal _test-output-stream  ""  "F - test-copy-byte-to-with-output: output should be empty")
9241     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'copy-byte-to' must not have any outputs"  "F - test-copy-byte-to-with-output: error message")
9242     # check that stop(1) was called
9243     (check-ints-equal *(edx+4) 2 "F - test-copy-byte-to-with-output: exit status")
9244     # don't restore from ebp
9245     81 0/subop/add %esp 8/imm32
9246     # . epilogue
9247     5d/pop-to-ebp
9248     c3/return
9250 test-copy-byte-to-with-invalid-output-type:
9251     # . prologue
9252     55/push-ebp
9253     89/<- %ebp 4/r32/esp
9254     # setup
9255     (clear-stream _test-input-stream)
9256     (clear-stream $_test-input-buffered-file->buffer)
9257     (clear-stream _test-output-stream)
9258     (clear-stream $_test-output-buffered-file->buffer)
9259     (clear-stream _test-error-stream)
9260     (clear-stream $_test-error-buffered-file->buffer)
9261     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
9262     68/push 0/imm32
9263     68/push 0/imm32
9264     89/<- %edx 4/r32/esp
9265     (tailor-exit-descriptor %edx 0x10)
9266     #
9267     (write _test-input-stream "fn foo {\n")
9268     (write _test-input-stream "  var x/eax: byte <- copy 0\n")
9269     (write _test-input-stream "  var y: int\n")
9270     (write _test-input-stream "  copy-byte-to y, x\n")
9271     (write _test-input-stream "}\n")
9272     # convert
9273     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
9274     # registers except esp clobbered at this point
9275     # restore ed
9276     89/<- %edx 4/r32/esp
9277     (flush _test-output-buffered-file)
9278     (flush _test-error-buffered-file)
9279 #?     # dump _test-error-stream {{{
9280 #?     (write 2 "^")
9281 #?     (write-stream 2 _test-error-stream)
9282 #?     (write 2 "$\n")
9283 #?     (rewind-stream _test-error-stream)
9284 #?     # }}}
9285     # check output
9286     (check-stream-equal _test-output-stream  ""  "F - test-copy-byte-to-with-invalid-output-type: output should be empty")
9287     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt copy-byte-to: 'y' must be a byte"  "F - test-copy-byte-to-with-invalid-output-type: error message")
9288     # check that stop(1) was called
9289     (check-ints-equal *(edx+4) 2 "F - test-copy-byte-to-with-invalid-output-type: exit status")
9290     # don't restore from ebp
9291     81 0/subop/add %esp 8/imm32
9292     # . epilogue
9293     5d/pop-to-ebp
9294     c3/return
9296 test-copy-byte-to-with-literal-inout:
9297     # . prologue
9298     55/push-ebp
9299     89/<- %ebp 4/r32/esp
9300     # setup
9301     (clear-stream _test-input-stream)
9302     (clear-stream $_test-input-buffered-file->buffer)
9303     (clear-stream _test-output-stream)
9304     (clear-stream $_test-output-buffered-file->buffer)
9305     (clear-stream _test-error-stream)
9306     (clear-stream $_test-error-buffered-file->buffer)
9307     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
9308     68/push 0/imm32
9309     68/push 0/imm32
9310     89/<- %edx 4/r32/esp
9311     (tailor-exit-descriptor %edx 0x10)
9312     #
9313     (write _test-input-stream "fn foo {\n")
9314     (write _test-input-stream "  var x/eax: (addr byte) <- copy 0\n")
9315     (write _test-input-stream "  copy-byte-to *x, 0\n")
9316     (write _test-input-stream "}\n")
9317     # convert
9318     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
9319     # registers except esp clobbered at this point
9320     # restore ed
9321     89/<- %edx 4/r32/esp
9322     (flush _test-output-buffered-file)
9323     (flush _test-error-buffered-file)
9324 #?     # dump _test-error-stream {{{
9325 #?     (write 2 "^")
9326 #?     (write-stream 2 _test-error-stream)
9327 #?     (write 2 "$\n")
9328 #?     (rewind-stream _test-error-stream)
9329 #?     # }}}
9330     # check output
9331     (check-stream-equal _test-output-stream  ""  "F - test-copy-byte-to-with-literal-inout: output should be empty")
9332     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt copy-byte-to: source (second inout) must be in a register"  "F - test-copy-byte-to-with-literal-inout: error message")
9333     # check that stop(1) was called
9334     (check-ints-equal *(edx+4) 2 "F - test-copy-byte-to-with-literal-inout: exit status")
9335     # don't restore from ebp
9336     81 0/subop/add %esp 8/imm32
9337     # . epilogue
9338     5d/pop-to-ebp
9339     c3/return
9341 test-copy-byte-to-deref-address:
9342     # . prologue
9343     55/push-ebp
9344     89/<- %ebp 4/r32/esp
9345     # setup
9346     (clear-stream _test-input-stream)
9347     (clear-stream $_test-input-buffered-file->buffer)
9348     (clear-stream _test-output-stream)
9349     (clear-stream $_test-output-buffered-file->buffer)
9350     #
9351     (write _test-input-stream "fn foo {\n")
9352     (write _test-input-stream "  var x/eax: byte <- copy 0\n")
9353     (write _test-input-stream "  var y/ecx: (addr byte) <- copy 0\n")
9354     (write _test-input-stream "  copy-byte-to *y, x\n")
9355     (write _test-input-stream "}\n")
9356     # convert
9357     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
9358     (flush _test-output-buffered-file)
9359     # no errors
9360     # . epilogue
9361     5d/pop-to-ebp
9362     c3/return
9364 test-copy-byte-to-from-non-scalar-inout:
9365     # . prologue
9366     55/push-ebp
9367     89/<- %ebp 4/r32/esp
9368     # setup
9369     (clear-stream _test-input-stream)
9370     (clear-stream $_test-input-buffered-file->buffer)
9371     (clear-stream _test-output-stream)
9372     (clear-stream $_test-output-buffered-file->buffer)
9373     (clear-stream _test-error-stream)
9374     (clear-stream $_test-error-buffered-file->buffer)
9375     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
9376     68/push 0/imm32
9377     68/push 0/imm32
9378     89/<- %edx 4/r32/esp
9379     (tailor-exit-descriptor %edx 0x10)
9380     #
9381     (write _test-input-stream "fn foo {\n")
9382     (write _test-input-stream "  var x: (handle int)\n")
9383     (write _test-input-stream "  var y/eax: (addr byte) <- copy 0\n")
9384     (write _test-input-stream "  copy-byte-to *y, x\n")
9385     (write _test-input-stream "}\n")
9386     # convert
9387     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
9388     # registers except esp clobbered at this point
9389     # restore ed
9390     89/<- %edx 4/r32/esp
9391     (flush _test-output-buffered-file)
9392     (flush _test-error-buffered-file)
9393 #?     # dump _test-error-stream {{{
9394 #?     (write 2 "^")
9395 #?     (write-stream 2 _test-error-stream)
9396 #?     (write 2 "$\n")
9397 #?     (rewind-stream _test-error-stream)
9398 #?     # }}}
9399     # check output
9400     (check-stream-equal _test-output-stream  ""  "F - test-copy-byte-to-from-non-scalar-inout: output should be empty")
9401     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt copy-byte-to: 'x' is too large to copy"  "F - test-copy-byte-to-from-non-scalar-inout: error message")
9402     # check that stop(1) was called
9403     (check-ints-equal *(edx+4) 2 "F - test-copy-byte-to-from-non-scalar-inout: exit status")
9404     # don't restore from ebp
9405     81 0/subop/add %esp 8/imm32
9406     # . epilogue
9407     5d/pop-to-ebp
9408     c3/return
9410 test-compare-with-no-inout:
9411     # . prologue
9412     55/push-ebp
9413     89/<- %ebp 4/r32/esp
9414     # setup
9415     (clear-stream _test-input-stream)
9416     (clear-stream $_test-input-buffered-file->buffer)
9417     (clear-stream _test-output-stream)
9418     (clear-stream $_test-output-buffered-file->buffer)
9419     (clear-stream _test-error-stream)
9420     (clear-stream $_test-error-buffered-file->buffer)
9421     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
9422     68/push 0/imm32
9423     68/push 0/imm32
9424     89/<- %edx 4/r32/esp
9425     (tailor-exit-descriptor %edx 0x10)
9426     #
9427     (write _test-input-stream "fn foo {\n")
9428     (write _test-input-stream "  var x: boolean\n")
9429     (write _test-input-stream "  compare\n")
9430     (write _test-input-stream "}\n")
9431     # convert
9432     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
9433     # registers except esp clobbered at this point
9434     # restore ed
9435     89/<- %edx 4/r32/esp
9436     (flush _test-output-buffered-file)
9437     (flush _test-error-buffered-file)
9438 #?     # dump _test-error-stream {{{
9439 #?     (write 2 "^")
9440 #?     (write-stream 2 _test-error-stream)
9441 #?     (write 2 "$\n")
9442 #?     (rewind-stream _test-error-stream)
9443 #?     # }}}
9444     # check output
9445     (check-stream-equal _test-output-stream  ""  "F - test-compare-with-no-inout: output should be empty")
9446     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'compare' must have two inouts"  "F - test-compare-with-no-inout: error message")
9447     # check that stop(1) was called
9448     (check-ints-equal *(edx+4) 2 "F - test-compare-with-no-inout: exit status")
9449     # don't restore from ebp
9450     81 0/subop/add %esp 8/imm32
9451     # . epilogue
9452     5d/pop-to-ebp
9453     c3/return
9455 test-compare-with-just-one-inout:
9456     # . prologue
9457     55/push-ebp
9458     89/<- %ebp 4/r32/esp
9459     # setup
9460     (clear-stream _test-input-stream)
9461     (clear-stream $_test-input-buffered-file->buffer)
9462     (clear-stream _test-output-stream)
9463     (clear-stream $_test-output-buffered-file->buffer)
9464     (clear-stream _test-error-stream)
9465     (clear-stream $_test-error-buffered-file->buffer)
9466     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
9467     68/push 0/imm32
9468     68/push 0/imm32
9469     89/<- %edx 4/r32/esp
9470     (tailor-exit-descriptor %edx 0x10)
9471     #
9472     (write _test-input-stream "fn foo {\n")
9473     (write _test-input-stream "  var x: boolean\n")
9474     (write _test-input-stream "  compare x\n")
9475     (write _test-input-stream "}\n")
9476     # convert
9477     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
9478     # registers except esp clobbered at this point
9479     # restore ed
9480     89/<- %edx 4/r32/esp
9481     (flush _test-output-buffered-file)
9482     (flush _test-error-buffered-file)
9483 #?     # dump _test-error-stream {{{
9484 #?     (write 2 "^")
9485 #?     (write-stream 2 _test-error-stream)
9486 #?     (write 2 "$\n")
9487 #?     (rewind-stream _test-error-stream)
9488 #?     # }}}
9489     # check output
9490     (check-stream-equal _test-output-stream  ""  "F - test-compare-with-just-one-inout: output should be empty")
9491     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'compare' must have two inouts"  "F - test-compare-with-just-one-inout: error message")
9492     # check that stop(1) was called
9493     (check-ints-equal *(edx+4) 2 "F - test-compare-with-just-one-inout: exit status")
9494     # don't restore from ebp
9495     81 0/subop/add %esp 8/imm32
9496     # . epilogue
9497     5d/pop-to-ebp
9498     c3/return
9500 test-compare-with-too-many-inouts:
9501     # . prologue
9502     55/push-ebp
9503     89/<- %ebp 4/r32/esp
9504     # setup
9505     (clear-stream _test-input-stream)
9506     (clear-stream $_test-input-buffered-file->buffer)
9507     (clear-stream _test-output-stream)
9508     (clear-stream $_test-output-buffered-file->buffer)
9509     (clear-stream _test-error-stream)
9510     (clear-stream $_test-error-buffered-file->buffer)
9511     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
9512     68/push 0/imm32
9513     68/push 0/imm32
9514     89/<- %edx 4/r32/esp
9515     (tailor-exit-descriptor %edx 0x10)
9516     #
9517     (write _test-input-stream "fn foo {\n")
9518     (write _test-input-stream "  var x: boolean\n")
9519     (write _test-input-stream "  compare x, 0, 0\n")
9520     (write _test-input-stream "}\n")
9521     # convert
9522     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
9523     # registers except esp clobbered at this point
9524     # restore ed
9525     89/<- %edx 4/r32/esp
9526     (flush _test-output-buffered-file)
9527     (flush _test-error-buffered-file)
9528 #?     # dump _test-error-stream {{{
9529 #?     (write 2 "^")
9530 #?     (write-stream 2 _test-error-stream)
9531 #?     (write 2 "$\n")
9532 #?     (rewind-stream _test-error-stream)
9533 #?     # }}}
9534     # check output
9535     (check-stream-equal _test-output-stream  ""  "F - test-compare-with-too-many-inouts: output should be empty")
9536     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'compare' must have two inouts"  "F - test-compare-with-too-many-inouts: error message")
9537     # check that stop(1) was called
9538     (check-ints-equal *(edx+4) 2 "F - test-compare-with-too-many-inouts: exit status")
9539     # don't restore from ebp
9540     81 0/subop/add %esp 8/imm32
9541     # . epilogue
9542     5d/pop-to-ebp
9543     c3/return
9545 test-compare-with-output:
9546     # . prologue
9547     55/push-ebp
9548     89/<- %ebp 4/r32/esp
9549     # setup
9550     (clear-stream _test-input-stream)
9551     (clear-stream $_test-input-buffered-file->buffer)
9552     (clear-stream _test-output-stream)
9553     (clear-stream $_test-output-buffered-file->buffer)
9554     (clear-stream _test-error-stream)
9555     (clear-stream $_test-error-buffered-file->buffer)
9556     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
9557     68/push 0/imm32
9558     68/push 0/imm32
9559     89/<- %edx 4/r32/esp
9560     (tailor-exit-descriptor %edx 0x10)
9561     #
9562     (write _test-input-stream "fn foo {\n")
9563     (write _test-input-stream "  var x/eax: boolean <- copy 0\n")
9564     (write _test-input-stream "  var y/ecx: boolean <- copy 0\n")
9565     (write _test-input-stream "  x <- compare y, 0\n")
9566     (write _test-input-stream "}\n")
9567     # convert
9568     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
9569     # registers except esp clobbered at this point
9570     # restore ed
9571     89/<- %edx 4/r32/esp
9572     (flush _test-output-buffered-file)
9573     (flush _test-error-buffered-file)
9574 #?     # dump _test-error-stream {{{
9575 #?     (write 2 "^")
9576 #?     (write-stream 2 _test-error-stream)
9577 #?     (write 2 "$\n")
9578 #?     (rewind-stream _test-error-stream)
9579 #?     # }}}
9580     # check output
9581     (check-stream-equal _test-output-stream  ""  "F - test-compare-with-output: output should be empty")
9582     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'compare' must not have any outputs"  "F - test-compare-with-output: error message")
9583     # check that stop(1) was called
9584     (check-ints-equal *(edx+4) 2 "F - test-compare-with-output: exit status")
9585     # don't restore from ebp
9586     81 0/subop/add %esp 8/imm32
9587     # . epilogue
9588     5d/pop-to-ebp
9589     c3/return
9591 test-compare-invalid-value-to-address:
9592     # . prologue
9593     55/push-ebp
9594     89/<- %ebp 4/r32/esp
9595     # setup
9596     (clear-stream _test-input-stream)
9597     (clear-stream $_test-input-buffered-file->buffer)
9598     (clear-stream _test-output-stream)
9599     (clear-stream $_test-output-buffered-file->buffer)
9600     (clear-stream _test-error-stream)
9601     (clear-stream $_test-error-buffered-file->buffer)
9602     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
9603     68/push 0/imm32
9604     68/push 0/imm32
9605     89/<- %edx 4/r32/esp
9606     (tailor-exit-descriptor %edx 0x10)
9607     #
9608     (write _test-input-stream "fn foo {\n")
9609     (write _test-input-stream "  var x/eax: int <- copy 0\n")
9610     (write _test-input-stream "  var y: (addr int)\n")
9611     (write _test-input-stream "  compare y, x\n")
9612     (write _test-input-stream "}\n")
9613     # convert
9614     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
9615     # registers except esp clobbered at this point
9616     # restore ed
9617     89/<- %edx 4/r32/esp
9618     (flush _test-output-buffered-file)
9619     (flush _test-error-buffered-file)
9620 #?     # dump _test-error-stream {{{
9621 #?     (write 2 "^")
9622 #?     (write-stream 2 _test-error-stream)
9623 #?     (write 2 "$\n")
9624 #?     (rewind-stream _test-error-stream)
9625 #?     # }}}
9626     # check output
9627     (check-stream-equal _test-output-stream  ""  "F - test-compare-invalid-value-to-address: output should be empty")
9628     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt compare: 'y' must be a non-addr non-offset scalar"  "F - test-compare-invalid-value-to-address: error message")
9629     # check that stop(1) was called
9630     (check-ints-equal *(edx+4) 2 "F - test-compare-invalid-value-to-address: exit status")
9631     # don't restore from ebp
9632     81 0/subop/add %esp 8/imm32
9633     # . epilogue
9634     5d/pop-to-ebp
9635     c3/return
9637 test-compare-address:
9638     # . prologue
9639     55/push-ebp
9640     89/<- %ebp 4/r32/esp
9641     # setup
9642     (clear-stream _test-input-stream)
9643     (clear-stream $_test-input-buffered-file->buffer)
9644     (clear-stream _test-output-stream)
9645     (clear-stream $_test-output-buffered-file->buffer)
9646     #
9647     (write _test-input-stream "fn foo {\n")
9648     (write _test-input-stream "  var x/eax: (addr int) <- copy 0\n")
9649     (write _test-input-stream "  var y/ecx: (addr int) <- copy 0\n")
9650     (write _test-input-stream "  compare y, x\n")
9651     (write _test-input-stream "}\n")
9652     # convert
9653     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
9654     (flush _test-output-buffered-file)
9655     # no errors
9656     # . epilogue
9657     5d/pop-to-ebp
9658     c3/return
9660 test-compare-deref-address:
9661     # . prologue
9662     55/push-ebp
9663     89/<- %ebp 4/r32/esp
9664     # setup
9665     (clear-stream _test-input-stream)
9666     (clear-stream $_test-input-buffered-file->buffer)
9667     (clear-stream _test-output-stream)
9668     (clear-stream $_test-output-buffered-file->buffer)
9669     #
9670     (write _test-input-stream "fn foo {\n")
9671     (write _test-input-stream "  var x/eax: (addr int) <- copy 0\n")
9672     (write _test-input-stream "  var y/ecx: (addr addr int) <- copy 0\n")
9673     (write _test-input-stream "  compare *y, x\n")
9674     (write _test-input-stream "}\n")
9675     # convert
9676     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
9677     (flush _test-output-buffered-file)
9678     # no errors
9679     # . epilogue
9680     5d/pop-to-ebp
9681     c3/return
9683 test-compare-two-vars-in-memory:
9684     # . prologue
9685     55/push-ebp
9686     89/<- %ebp 4/r32/esp
9687     # setup
9688     (clear-stream _test-input-stream)
9689     (clear-stream $_test-input-buffered-file->buffer)
9690     (clear-stream _test-output-stream)
9691     (clear-stream $_test-output-buffered-file->buffer)
9692     (clear-stream _test-error-stream)
9693     (clear-stream $_test-error-buffered-file->buffer)
9694     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
9695     68/push 0/imm32
9696     68/push 0/imm32
9697     89/<- %edx 4/r32/esp
9698     (tailor-exit-descriptor %edx 0x10)
9699     #
9700     (write _test-input-stream "fn foo {\n")
9701     (write _test-input-stream "  var x: boolean\n")
9702     (write _test-input-stream "  compare x, x\n")
9703     (write _test-input-stream "}\n")
9704     # convert
9705     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
9706     # registers except esp clobbered at this point
9707     # restore ed
9708     89/<- %edx 4/r32/esp
9709     (flush _test-output-buffered-file)
9710     (flush _test-error-buffered-file)
9711 #?     # dump _test-error-stream {{{
9712 #?     (write 2 "^")
9713 #?     (write-stream 2 _test-error-stream)
9714 #?     (write 2 "$\n")
9715 #?     (rewind-stream _test-error-stream)
9716 #?     # }}}
9717     # check output
9718     (check-stream-equal _test-output-stream  ""  "F - test-compare-two-vars-in-memory: output should be empty")
9719     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt compare: both inouts are in memory"  "F - test-compare-two-vars-in-memory: error message")
9720     # check that stop(1) was called
9721     (check-ints-equal *(edx+4) 2 "F - test-compare-two-vars-in-memory: exit status")
9722     # don't restore from ebp
9723     81 0/subop/add %esp 8/imm32
9724     # . epilogue
9725     5d/pop-to-ebp
9726     c3/return
9728 test-compare-non-scalar:
9729     # . prologue
9730     55/push-ebp
9731     89/<- %ebp 4/r32/esp
9732     # setup
9733     (clear-stream _test-input-stream)
9734     (clear-stream $_test-input-buffered-file->buffer)
9735     (clear-stream _test-output-stream)
9736     (clear-stream $_test-output-buffered-file->buffer)
9737     (clear-stream _test-error-stream)
9738     (clear-stream $_test-error-buffered-file->buffer)
9739     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
9740     68/push 0/imm32
9741     68/push 0/imm32
9742     89/<- %edx 4/r32/esp
9743     (tailor-exit-descriptor %edx 0x10)
9744     #
9745     (write _test-input-stream "fn foo {\n")
9746     (write _test-input-stream "  var x: (handle int)\n")
9747     (write _test-input-stream "  var y: int\n")
9748     (write _test-input-stream "  compare y, x\n")
9749     (write _test-input-stream "}\n")
9750     # convert
9751     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
9752     # registers except esp clobbered at this point
9753     # restore ed
9754     89/<- %edx 4/r32/esp
9755     (flush _test-output-buffered-file)
9756     (flush _test-error-buffered-file)
9757 #?     # dump _test-error-stream {{{
9758 #?     (write 2 "^")
9759 #?     (write-stream 2 _test-error-stream)
9760 #?     (write 2 "$\n")
9761 #?     (rewind-stream _test-error-stream)
9762 #?     # }}}
9763     # check output
9764     (check-stream-equal _test-output-stream  ""  "F - test-compare-non-scalar: output should be empty")
9765 #?     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt compare: 'x' is too large to compare"  "F - test-compare-non-scalar: error message")
9766     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt compare: both inouts are in memory"  "F - test-compare-non-scalar: error message")
9767     # check that stop(1) was called
9768     (check-ints-equal *(edx+4) 2 "F - test-compare-non-scalar: exit status")
9769     # don't restore from ebp
9770     81 0/subop/add %esp 8/imm32
9771     # . epilogue
9772     5d/pop-to-ebp
9773     c3/return
9775 test-compare-with-string-literal:
9776     # . prologue
9777     55/push-ebp
9778     89/<- %ebp 4/r32/esp
9779     # setup
9780     (clear-stream _test-input-stream)
9781     (clear-stream $_test-input-buffered-file->buffer)
9782     (clear-stream _test-output-stream)
9783     (clear-stream $_test-output-buffered-file->buffer)
9784     (clear-stream _test-error-stream)
9785     (clear-stream $_test-error-buffered-file->buffer)
9786     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
9787     68/push 0/imm32
9788     68/push 0/imm32
9789     89/<- %edx 4/r32/esp
9790     (tailor-exit-descriptor %edx 0x10)
9791     #
9792     (write _test-input-stream "fn foo {\n")
9793     (write _test-input-stream "  var x/eax: (addr array byte) <- copy 0\n")
9794     (write _test-input-stream "  compare x, \"abc\"\n")
9795     (write _test-input-stream "}\n")
9796     # convert
9797     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
9798     # registers except esp clobbered at this point
9799     # restore ed
9800     89/<- %edx 4/r32/esp
9801     (flush _test-output-buffered-file)
9802     (flush _test-error-buffered-file)
9803 #?     # dump _test-error-stream {{{
9804 #?     (write 2 "^")
9805 #?     (write-stream 2 _test-error-stream)
9806 #?     (write 2 "$\n")
9807 #?     (rewind-stream _test-error-stream)
9808 #?     # }}}
9809     # check output
9810     (check-stream-equal _test-output-stream  ""  "F - test-compare-with-string-literal: output should be empty")
9811     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt compare: string literal \"abc\" is not supported; use the string-equal? function"  "F - test-compare-with-string-literal: error message")
9812     # check that stop(1) was called
9813     (check-ints-equal *(edx+4) 2 "F - test-compare-with-string-literal: exit status")
9814     # don't restore from ebp
9815     81 0/subop/add %esp 8/imm32
9816     # . epilogue
9817     5d/pop-to-ebp
9818     c3/return
9820 test-address-with-no-inout:
9821     # . prologue
9822     55/push-ebp
9823     89/<- %ebp 4/r32/esp
9824     # setup
9825     (clear-stream _test-input-stream)
9826     (clear-stream $_test-input-buffered-file->buffer)
9827     (clear-stream _test-output-stream)
9828     (clear-stream $_test-output-buffered-file->buffer)
9829     (clear-stream _test-error-stream)
9830     (clear-stream $_test-error-buffered-file->buffer)
9831     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
9832     68/push 0/imm32
9833     68/push 0/imm32
9834     89/<- %edx 4/r32/esp
9835     (tailor-exit-descriptor %edx 0x10)
9836     #
9837     (write _test-input-stream "fn foo {\n")
9838     (write _test-input-stream "  var x/eax: boolean <- address\n")
9839     (write _test-input-stream "}\n")
9840     # convert
9841     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
9842     # registers except esp clobbered at this point
9843     # restore ed
9844     89/<- %edx 4/r32/esp
9845     (flush _test-output-buffered-file)
9846     (flush _test-error-buffered-file)
9847 #?     # dump _test-error-stream {{{
9848 #?     (write 2 "^")
9849 #?     (write-stream 2 _test-error-stream)
9850 #?     (write 2 "$\n")
9851 #?     (rewind-stream _test-error-stream)
9852 #?     # }}}
9853     # check output
9854     (check-stream-equal _test-output-stream  ""  "F - test-address-with-no-inout: output should be empty")
9855     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'address' expects an inout"  "F - test-address-with-no-inout: error message")
9856     # check that stop(1) was called
9857     (check-ints-equal *(edx+4) 2 "F - test-address-with-no-inout: exit status")
9858     # don't restore from ebp
9859     81 0/subop/add %esp 8/imm32
9860     # . epilogue
9861     5d/pop-to-ebp
9862     c3/return
9864 test-address-with-multiple-inouts:
9865     # . prologue
9866     55/push-ebp
9867     89/<- %ebp 4/r32/esp
9868     # setup
9869     (clear-stream _test-input-stream)
9870     (clear-stream $_test-input-buffered-file->buffer)
9871     (clear-stream _test-output-stream)
9872     (clear-stream $_test-output-buffered-file->buffer)
9873     (clear-stream _test-error-stream)
9874     (clear-stream $_test-error-buffered-file->buffer)
9875     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
9876     68/push 0/imm32
9877     68/push 0/imm32
9878     89/<- %edx 4/r32/esp
9879     (tailor-exit-descriptor %edx 0x10)
9880     #
9881     (write _test-input-stream "fn foo {\n")
9882     (write _test-input-stream "  var x/eax: boolean <- address 0, 0\n")
9883     (write _test-input-stream "}\n")
9884     # convert
9885     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
9886     # registers except esp clobbered at this point
9887     # restore ed
9888     89/<- %edx 4/r32/esp
9889     (flush _test-output-buffered-file)
9890     (flush _test-error-buffered-file)
9891 #?     # dump _test-error-stream {{{
9892 #?     (write 2 "^")
9893 #?     (write-stream 2 _test-error-stream)
9894 #?     (write 2 "$\n")
9895 #?     (rewind-stream _test-error-stream)
9896 #?     # }}}
9897     # check output
9898     (check-stream-equal _test-output-stream  ""  "F - test-address-with-multiple-inouts: output should be empty")
9899     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'address' must have just one inout"  "F - test-address-with-multiple-inouts: error message")
9900     # check that stop(1) was called
9901     (check-ints-equal *(edx+4) 2 "F - test-address-with-multiple-inouts: exit status")
9902     # don't restore from ebp
9903     81 0/subop/add %esp 8/imm32
9904     # . epilogue
9905     5d/pop-to-ebp
9906     c3/return
9908 test-address-with-no-output:
9909     # . prologue
9910     55/push-ebp
9911     89/<- %ebp 4/r32/esp
9912     # setup
9913     (clear-stream _test-input-stream)
9914     (clear-stream $_test-input-buffered-file->buffer)
9915     (clear-stream _test-output-stream)
9916     (clear-stream $_test-output-buffered-file->buffer)
9917     (clear-stream _test-error-stream)
9918     (clear-stream $_test-error-buffered-file->buffer)
9919     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
9920     68/push 0/imm32
9921     68/push 0/imm32
9922     89/<- %edx 4/r32/esp
9923     (tailor-exit-descriptor %edx 0x10)
9924     #
9925     (write _test-input-stream "fn foo {\n")
9926     (write _test-input-stream "  address 0\n")
9927     (write _test-input-stream "}\n")
9928     # convert
9929     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
9930     # registers except esp clobbered at this point
9931     # restore ed
9932     89/<- %edx 4/r32/esp
9933     (flush _test-output-buffered-file)
9934     (flush _test-error-buffered-file)
9935 #?     # dump _test-error-stream {{{
9936 #?     (write 2 "^")
9937 #?     (write-stream 2 _test-error-stream)
9938 #?     (write 2 "$\n")
9939 #?     (rewind-stream _test-error-stream)
9940 #?     # }}}
9941     # check output
9942     (check-stream-equal _test-output-stream  ""  "F - test-address-with-no-output: output should be empty")
9943     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'address' expects an output"  "F - test-address-with-no-output: error message")
9944     # check that stop(1) was called
9945     (check-ints-equal *(edx+4) 2 "F - test-address-with-no-output: exit status")
9946     # don't restore from ebp
9947     81 0/subop/add %esp 8/imm32
9948     # . epilogue
9949     5d/pop-to-ebp
9950     c3/return
9952 test-address-with-multiple-outputs:
9953     # . prologue
9954     55/push-ebp
9955     89/<- %ebp 4/r32/esp
9956     # setup
9957     (clear-stream _test-input-stream)
9958     (clear-stream $_test-input-buffered-file->buffer)
9959     (clear-stream _test-output-stream)
9960     (clear-stream $_test-output-buffered-file->buffer)
9961     (clear-stream _test-error-stream)
9962     (clear-stream $_test-error-buffered-file->buffer)
9963     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
9964     68/push 0/imm32
9965     68/push 0/imm32
9966     89/<- %edx 4/r32/esp
9967     (tailor-exit-descriptor %edx 0x10)
9968     #
9969     (write _test-input-stream "fn foo {\n")
9970     (write _test-input-stream "  var x/eax: boolean <- copy 0\n")
9971     (write _test-input-stream "  var y/ecx: boolean <- copy 0\n")
9972     (write _test-input-stream "  x, y <- address 0\n")
9973     (write _test-input-stream "}\n")
9974     # convert
9975     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
9976     # registers except esp clobbered at this point
9977     # restore ed
9978     89/<- %edx 4/r32/esp
9979     (flush _test-output-buffered-file)
9980     (flush _test-error-buffered-file)
9981 #?     # dump _test-error-stream {{{
9982 #?     (write 2 "^")
9983 #?     (write-stream 2 _test-error-stream)
9984 #?     (write 2 "$\n")
9985 #?     (rewind-stream _test-error-stream)
9986 #?     # }}}
9987     # check output
9988     (check-stream-equal _test-output-stream  ""  "F - test-address-with-multiple-outputs: output should be empty")
9989     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'address' must have just one output"  "F - test-address-with-multiple-outputs: error message")
9990     # check that stop(1) was called
9991     (check-ints-equal *(edx+4) 2 "F - test-address-with-multiple-outputs: exit status")
9992     # don't restore from ebp
9993     81 0/subop/add %esp 8/imm32
9994     # . epilogue
9995     5d/pop-to-ebp
9996     c3/return
9998 # silly but it works
9999 test-address-of-deref:
10000     # . prologue
10001     55/push-ebp
10002     89/<- %ebp 4/r32/esp
10003     # setup
10004     (clear-stream _test-input-stream)
10005     (clear-stream $_test-input-buffered-file->buffer)
10006     (clear-stream _test-output-stream)
10007     (clear-stream $_test-output-buffered-file->buffer)
10008     #
10009     (write _test-input-stream "fn foo {\n")
10010     (write _test-input-stream "  var x/eax: (addr int) <- copy 0\n")
10011     (write _test-input-stream "  var y/ecx: (addr int) <- address *x\n")
10012     (write _test-input-stream "}\n")
10013     # convert
10014     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
10015     (flush _test-output-buffered-file)
10016     # no errors
10017     # . epilogue
10018     5d/pop-to-ebp
10019     c3/return
10021 test-address-to-non-register:
10022     # . prologue
10023     55/push-ebp
10024     89/<- %ebp 4/r32/esp
10025     # setup
10026     (clear-stream _test-input-stream)
10027     (clear-stream $_test-input-buffered-file->buffer)
10028     (clear-stream _test-output-stream)
10029     (clear-stream $_test-output-buffered-file->buffer)
10030     (clear-stream _test-error-stream)
10031     (clear-stream $_test-error-buffered-file->buffer)
10032     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
10033     68/push 0/imm32
10034     68/push 0/imm32
10035     89/<- %edx 4/r32/esp
10036     (tailor-exit-descriptor %edx 0x10)
10037     #
10038     (write _test-input-stream "fn foo {\n")
10039     (write _test-input-stream "  var x: (addr int)\n")
10040     (write _test-input-stream "  x <- address 0\n")
10041     (write _test-input-stream "}\n")
10042     # convert
10043     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
10044     # registers except esp clobbered at this point
10045     # restore ed
10046     89/<- %edx 4/r32/esp
10047     (flush _test-output-buffered-file)
10048     (flush _test-error-buffered-file)
10049 #?     # dump _test-error-stream {{{
10050 #?     (write 2 "^")
10051 #?     (write-stream 2 _test-error-stream)
10052 #?     (write 2 "$\n")
10053 #?     (rewind-stream _test-error-stream)
10054 #?     # }}}
10055     # check output
10056     (check-stream-equal _test-output-stream  ""  "F - test-address-to-non-register: output should be empty")
10057     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt address: output 'x' not in a register"  "F - test-address-to-non-register: error message")
10058     # check that stop(1) was called
10059     (check-ints-equal *(edx+4) 2 "F - test-address-to-non-register: exit status")
10060     # don't restore from ebp
10061     81 0/subop/add %esp 8/imm32
10062     # . epilogue
10063     5d/pop-to-ebp
10064     c3/return
10066 test-address-with-wrong-type:
10067     # . prologue
10068     55/push-ebp
10069     89/<- %ebp 4/r32/esp
10070     # setup
10071     (clear-stream _test-input-stream)
10072     (clear-stream $_test-input-buffered-file->buffer)
10073     (clear-stream _test-output-stream)
10074     (clear-stream $_test-output-buffered-file->buffer)
10075     (clear-stream _test-error-stream)
10076     (clear-stream $_test-error-buffered-file->buffer)
10077     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
10078     68/push 0/imm32
10079     68/push 0/imm32
10080     89/<- %edx 4/r32/esp
10081     (tailor-exit-descriptor %edx 0x10)
10082     #
10083     (write _test-input-stream "fn foo {\n")
10084     (write _test-input-stream "  var x: int\n")
10085     (write _test-input-stream "  var y/eax: (addr boolean) <- address x\n")
10086     (write _test-input-stream "}\n")
10087     # convert
10088     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
10089     # registers except esp clobbered at this point
10090     # restore ed
10091     89/<- %edx 4/r32/esp
10092     (flush _test-output-buffered-file)
10093     (flush _test-error-buffered-file)
10094 #?     # dump _test-error-stream {{{
10095 #?     (write 2 "^")
10096 #?     (write-stream 2 _test-error-stream)
10097 #?     (write 2 "$\n")
10098 #?     (rewind-stream _test-error-stream)
10099 #?     # }}}
10100     # check output
10101     (check-stream-equal _test-output-stream  ""  "F - test-address-with-wrong-type: output should be empty")
10102     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt address: output 'y' cannot hold address of 'x'"  "F - test-address-with-wrong-type: error message")
10103     # check that stop(1) was called
10104     (check-ints-equal *(edx+4) 2 "F - test-address-with-wrong-type: exit status")
10105     # don't restore from ebp
10106     81 0/subop/add %esp 8/imm32
10107     # . epilogue
10108     5d/pop-to-ebp
10109     c3/return
10111 test-address-with-right-type-for-array:
10112     # . prologue
10113     55/push-ebp
10114     89/<- %ebp 4/r32/esp
10115     # setup
10116     (clear-stream _test-input-stream)
10117     (clear-stream $_test-input-buffered-file->buffer)
10118     (clear-stream _test-output-stream)
10119     (clear-stream $_test-output-buffered-file->buffer)
10120     #
10121     (write _test-input-stream "fn foo {\n")
10122     (write _test-input-stream "  var x: (array int 3)\n")
10123     (write _test-input-stream "  var y/eax: (addr array int) <- address x\n")
10124     (write _test-input-stream "}\n")
10125     # convert
10126     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
10127     (flush _test-output-buffered-file)
10128     # no errors
10129     # . epilogue
10130     89/<- %esp 5/r32/ebp
10131     5d/pop-to-ebp
10132     c3/return
10134 test-address-with-right-type-for-stream:
10135     # . prologue
10136     55/push-ebp
10137     89/<- %ebp 4/r32/esp
10138     # setup
10139     (clear-stream _test-input-stream)
10140     (clear-stream $_test-input-buffered-file->buffer)
10141     (clear-stream _test-output-stream)
10142     (clear-stream $_test-output-buffered-file->buffer)
10143     #
10144     (write _test-input-stream "fn foo {\n")
10145     (write _test-input-stream "  var x: (stream int 3)\n")
10146     (write _test-input-stream "  var y/eax: (addr stream int) <- address x\n")
10147     (write _test-input-stream "}\n")
10148     # convert
10149     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
10150     (flush _test-output-buffered-file)
10151     # no errors
10152     # . epilogue
10153     89/<- %esp 5/r32/ebp
10154     5d/pop-to-ebp
10155     c3/return
10157 test-get-with-wrong-field:
10158     # . prologue
10159     55/push-ebp
10160     89/<- %ebp 4/r32/esp
10161     # setup
10162     (clear-stream _test-input-stream)
10163     (clear-stream $_test-input-buffered-file->buffer)
10164     (clear-stream _test-output-stream)
10165     (clear-stream $_test-output-buffered-file->buffer)
10166     (clear-stream _test-error-stream)
10167     (clear-stream $_test-error-buffered-file->buffer)
10168     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
10169     68/push 0/imm32
10170     68/push 0/imm32
10171     89/<- %edx 4/r32/esp
10172     (tailor-exit-descriptor %edx 0x10)
10173     #
10174     (write _test-input-stream "fn foo {\n")
10175     (write _test-input-stream "  var a: t\n")
10176     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
10177     (write _test-input-stream "}\n")
10178     (write _test-input-stream "type t {\n")
10179     (write _test-input-stream "  x: int\n")
10180     (write _test-input-stream "}\n")
10181     # convert
10182     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
10183     # registers except esp clobbered at this point
10184     # restore ed
10185     89/<- %edx 4/r32/esp
10186     (flush _test-output-buffered-file)
10187     (flush _test-error-buffered-file)
10188 #?     # dump _test-error-stream {{{
10189 #?     (write 2 "^")
10190 #?     (write-stream 2 _test-error-stream)
10191 #?     (write 2 "$\n")
10192 #?     (rewind-stream _test-error-stream)
10193 #?     # }}}
10194     # check output
10195     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-field: output should be empty")
10196     (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")
10197     # check that stop(1) was called
10198     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-field: exit status")
10199     # don't restore from ebp
10200     81 0/subop/add %esp 8/imm32
10201     # . epilogue
10202     5d/pop-to-ebp
10203     c3/return
10205 test-get-with-wrong-base-type:
10206     # . prologue
10207     55/push-ebp
10208     89/<- %ebp 4/r32/esp
10209     # setup
10210     (clear-stream _test-input-stream)
10211     (clear-stream $_test-input-buffered-file->buffer)
10212     (clear-stream _test-output-stream)
10213     (clear-stream $_test-output-buffered-file->buffer)
10214     (clear-stream _test-error-stream)
10215     (clear-stream $_test-error-buffered-file->buffer)
10216     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
10217     68/push 0/imm32
10218     68/push 0/imm32
10219     89/<- %edx 4/r32/esp
10220     (tailor-exit-descriptor %edx 0x10)
10221     #
10222     (write _test-input-stream "fn foo {\n")
10223     (write _test-input-stream "  var a: int\n")
10224     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
10225     (write _test-input-stream "}\n")
10226     # convert
10227     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
10228     # registers except esp clobbered at this point
10229     # restore ed
10230     89/<- %edx 4/r32/esp
10231     (flush _test-output-buffered-file)
10232     (flush _test-error-buffered-file)
10233 #?     # dump _test-error-stream {{{
10234 #?     (write 2 "^")
10235 #?     (write-stream 2 _test-error-stream)
10236 #?     (write 2 "$\n")
10237 #?     (rewind-stream _test-error-stream)
10238 #?     # }}}
10239     # check output
10240     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-base-type: output should be empty")
10241     (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")
10242     # check that stop(1) was called
10243     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-base-type: exit status")
10244     # don't restore from ebp
10245     81 0/subop/add %esp 8/imm32
10246     # . epilogue
10247     5d/pop-to-ebp
10248     c3/return
10250 test-get-with-wrong-base-type-2:
10251     # . prologue
10252     55/push-ebp
10253     89/<- %ebp 4/r32/esp
10254     # setup
10255     (clear-stream _test-input-stream)
10256     (clear-stream $_test-input-buffered-file->buffer)
10257     (clear-stream _test-output-stream)
10258     (clear-stream $_test-output-buffered-file->buffer)
10259     (clear-stream _test-error-stream)
10260     (clear-stream $_test-error-buffered-file->buffer)
10261     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
10262     68/push 0/imm32
10263     68/push 0/imm32
10264     89/<- %edx 4/r32/esp
10265     (tailor-exit-descriptor %edx 0x10)
10266     #
10267     (write _test-input-stream "fn foo {\n")
10268     (write _test-input-stream "  var a: (addr t)\n")
10269     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
10270     (write _test-input-stream "}\n")
10271     (write _test-input-stream "type t {\n")
10272     (write _test-input-stream "  x: int\n")
10273     (write _test-input-stream "}\n")
10274     # convert
10275     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
10276     # registers except esp clobbered at this point
10277     # restore ed
10278     89/<- %edx 4/r32/esp
10279     (flush _test-output-buffered-file)
10280     (flush _test-error-buffered-file)
10281 #?     # dump _test-error-stream {{{
10282 #?     (write 2 "^")
10283 #?     (write-stream 2 _test-error-stream)
10284 #?     (write 2 "$\n")
10285 #?     (rewind-stream _test-error-stream)
10286 #?     # }}}
10287     # check output
10288     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-base-type-2: output should be empty")
10289     (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")
10290     # check that stop(1) was called
10291     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-base-type-2: exit status")
10292     # don't restore from ebp
10293     81 0/subop/add %esp 8/imm32
10294     # . epilogue
10295     5d/pop-to-ebp
10296     c3/return
10298 test-get-with-wrong-base-type-3:
10299     # . prologue
10300     55/push-ebp
10301     89/<- %ebp 4/r32/esp
10302     # setup
10303     (clear-stream _test-input-stream)
10304     (clear-stream $_test-input-buffered-file->buffer)
10305     (clear-stream _test-output-stream)
10306     (clear-stream $_test-output-buffered-file->buffer)
10307     (clear-stream _test-error-stream)
10308     (clear-stream $_test-error-buffered-file->buffer)
10309     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
10310     68/push 0/imm32
10311     68/push 0/imm32
10312     89/<- %edx 4/r32/esp
10313     (tailor-exit-descriptor %edx 0x10)
10314     #
10315     (write _test-input-stream "fn foo {\n")
10316     (write _test-input-stream "  var a: (handle int)\n")
10317     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
10318     (write _test-input-stream "}\n")
10319     # convert
10320     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
10321     # registers except esp clobbered at this point
10322     # restore ed
10323     89/<- %edx 4/r32/esp
10324     (flush _test-output-buffered-file)
10325     (flush _test-error-buffered-file)
10326 #?     # dump _test-error-stream {{{
10327 #?     (write 2 "^")
10328 #?     (write-stream 2 _test-error-stream)
10329 #?     (write 2 "$\n")
10330 #?     (rewind-stream _test-error-stream)
10331 #?     # }}}
10332     # check output
10333     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-base-type-3: output should be empty")
10334     (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-3: error message")
10335     # check that stop(1) was called
10336     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-base-type-3: exit status")
10337     # don't restore from ebp
10338     81 0/subop/add %esp 8/imm32
10339     # . epilogue
10340     5d/pop-to-ebp
10341     c3/return
10343 test-get-with-wrong-offset-type:
10344     # . prologue
10345     55/push-ebp
10346     89/<- %ebp 4/r32/esp
10347     # setup
10348     (clear-stream _test-input-stream)
10349     (clear-stream $_test-input-buffered-file->buffer)
10350     (clear-stream _test-output-stream)
10351     (clear-stream $_test-output-buffered-file->buffer)
10352     (clear-stream _test-error-stream)
10353     (clear-stream $_test-error-buffered-file->buffer)
10354     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
10355     68/push 0/imm32
10356     68/push 0/imm32
10357     89/<- %edx 4/r32/esp
10358     (tailor-exit-descriptor %edx 0x10)
10359     #
10360     (write _test-input-stream "fn foo {\n")
10361     (write _test-input-stream "  var a: t\n")
10362     (write _test-input-stream "  var b: int\n")
10363     (write _test-input-stream "  var c/ecx: (addr int) <- get a, b\n")
10364     (write _test-input-stream "}\n")
10365     (write _test-input-stream "type t {\n")
10366     (write _test-input-stream "  x: int\n")
10367     (write _test-input-stream "}\n")
10368     # convert
10369     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
10370     # registers except esp clobbered at this point
10371     # restore ed
10372     89/<- %edx 4/r32/esp
10373     (flush _test-output-buffered-file)
10374     (flush _test-error-buffered-file)
10375 #?     # dump _test-error-stream {{{
10376 #?     (write 2 "^")
10377 #?     (write-stream 2 _test-error-stream)
10378 #?     (write 2 "$\n")
10379 #?     (rewind-stream _test-error-stream)
10380 #?     # }}}
10381     # check output
10382     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-offset-type: output should be empty")
10383     (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")
10384     # check that stop(1) was called
10385     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-offset-type: exit status")
10386     # don't restore from ebp
10387     81 0/subop/add %esp 8/imm32
10388     # . epilogue
10389     5d/pop-to-ebp
10390     c3/return
10392 test-get-with-wrong-output-type:
10393     # . prologue
10394     55/push-ebp
10395     89/<- %ebp 4/r32/esp
10396     # setup
10397     (clear-stream _test-input-stream)
10398     (clear-stream $_test-input-buffered-file->buffer)
10399     (clear-stream _test-output-stream)
10400     (clear-stream $_test-output-buffered-file->buffer)
10401     (clear-stream _test-error-stream)
10402     (clear-stream $_test-error-buffered-file->buffer)
10403     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
10404     68/push 0/imm32
10405     68/push 0/imm32
10406     89/<- %edx 4/r32/esp
10407     (tailor-exit-descriptor %edx 0x10)
10408     #
10409     (write _test-input-stream "fn foo {\n")
10410     (write _test-input-stream "  var a: t\n")
10411     (write _test-input-stream "  var c: (addr int)\n")
10412     (write _test-input-stream "  c <- get a, x\n")
10413     (write _test-input-stream "}\n")
10414     (write _test-input-stream "type t {\n")
10415     (write _test-input-stream "  x: int\n")
10416     (write _test-input-stream "}\n")
10417     # convert
10418     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
10419     # registers except esp clobbered at this point
10420     # restore ed
10421     89/<- %edx 4/r32/esp
10422     (flush _test-output-buffered-file)
10423     (flush _test-error-buffered-file)
10424 #?     # dump _test-error-stream {{{
10425 #?     (write 2 "^")
10426 #?     (write-stream 2 _test-error-stream)
10427 #?     (write 2 "$\n")
10428 #?     (rewind-stream _test-error-stream)
10429 #?     # }}}
10430     # check output
10431     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type: output should be empty")
10432     (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")
10433     # check that stop(1) was called
10434     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type: exit status")
10435     # don't restore from ebp
10436     81 0/subop/add %esp 8/imm32
10437     # . epilogue
10438     5d/pop-to-ebp
10439     c3/return
10441 test-get-with-wrong-output-type-2:
10442     # . prologue
10443     55/push-ebp
10444     89/<- %ebp 4/r32/esp
10445     # setup
10446     (clear-stream _test-input-stream)
10447     (clear-stream $_test-input-buffered-file->buffer)
10448     (clear-stream _test-output-stream)
10449     (clear-stream $_test-output-buffered-file->buffer)
10450     (clear-stream _test-error-stream)
10451     (clear-stream $_test-error-buffered-file->buffer)
10452     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
10453     68/push 0/imm32
10454     68/push 0/imm32
10455     89/<- %edx 4/r32/esp
10456     (tailor-exit-descriptor %edx 0x10)
10457     #
10458     (write _test-input-stream "fn foo {\n")
10459     (write _test-input-stream "  var a: t\n")
10460     (write _test-input-stream "  var c/ecx: int <- get a, x\n")
10461     (write _test-input-stream "}\n")
10462     (write _test-input-stream "type t {\n")
10463     (write _test-input-stream "  x: int\n")
10464     (write _test-input-stream "}\n")
10465     # convert
10466     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
10467     # registers except esp clobbered at this point
10468     # restore ed
10469     89/<- %edx 4/r32/esp
10470     (flush _test-output-buffered-file)
10471     (flush _test-error-buffered-file)
10472 #?     # dump _test-error-stream {{{
10473 #?     (write 2 "^")
10474 #?     (write-stream 2 _test-error-stream)
10475 #?     (write 2 "$\n")
10476 #?     (rewind-stream _test-error-stream)
10477 #?     # }}}
10478     # check output
10479     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-2: output should be empty")
10480     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: output must be an addr"  "F - test-get-with-wrong-output-type-2: error message")
10481     # check that stop(1) was called
10482     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-2: exit status")
10483     # don't restore from ebp
10484     81 0/subop/add %esp 8/imm32
10485     # . epilogue
10486     5d/pop-to-ebp
10487     c3/return
10489 test-get-with-wrong-output-type-3:
10490     # . prologue
10491     55/push-ebp
10492     89/<- %ebp 4/r32/esp
10493     # setup
10494     (clear-stream _test-input-stream)
10495     (clear-stream $_test-input-buffered-file->buffer)
10496     (clear-stream _test-output-stream)
10497     (clear-stream $_test-output-buffered-file->buffer)
10498     (clear-stream _test-error-stream)
10499     (clear-stream $_test-error-buffered-file->buffer)
10500     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
10501     68/push 0/imm32
10502     68/push 0/imm32
10503     89/<- %edx 4/r32/esp
10504     (tailor-exit-descriptor %edx 0x10)
10505     #
10506     (write _test-input-stream "fn foo {\n")
10507     (write _test-input-stream "  var a: t\n")
10508     (write _test-input-stream "  var c/ecx: (array int) <- get a, x\n")
10509     (write _test-input-stream "}\n")
10510     (write _test-input-stream "type t {\n")
10511     (write _test-input-stream "  x: int\n")
10512     (write _test-input-stream "}\n")
10513     # convert
10514     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
10515     # registers except esp clobbered at this point
10516     # restore ed
10517     89/<- %edx 4/r32/esp
10518     (flush _test-output-buffered-file)
10519     (flush _test-error-buffered-file)
10520 #?     # dump _test-error-stream {{{
10521 #?     (write 2 "^")
10522 #?     (write-stream 2 _test-error-stream)
10523 #?     (write 2 "$\n")
10524 #?     (rewind-stream _test-error-stream)
10525 #?     # }}}
10526     # check output
10527     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-3: output should be empty")
10528     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: output must be an addr"  "F - test-get-with-wrong-output-type-3: error message")
10529     # check that stop(1) was called
10530     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-3: exit status")
10531     # don't restore from ebp
10532     81 0/subop/add %esp 8/imm32
10533     # . epilogue
10534     5d/pop-to-ebp
10535     c3/return
10537 test-get-with-wrong-output-type-4:
10538     # . prologue
10539     55/push-ebp
10540     89/<- %ebp 4/r32/esp
10541     # setup
10542     (clear-stream _test-input-stream)
10543     (clear-stream $_test-input-buffered-file->buffer)
10544     (clear-stream _test-output-stream)
10545     (clear-stream $_test-output-buffered-file->buffer)
10546     (clear-stream _test-error-stream)
10547     (clear-stream $_test-error-buffered-file->buffer)
10548     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
10549     68/push 0/imm32
10550     68/push 0/imm32
10551     89/<- %edx 4/r32/esp
10552     (tailor-exit-descriptor %edx 0x10)
10553     #
10554     (write _test-input-stream "fn foo {\n")
10555     (write _test-input-stream "  var a: t\n")
10556     (write _test-input-stream "  var c/ecx: (addr boolean) <- get a, x\n")
10557     (write _test-input-stream "}\n")
10558     (write _test-input-stream "type t {\n")
10559     (write _test-input-stream "  x: int\n")
10560     (write _test-input-stream "}\n")
10561     # convert
10562     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
10563     # registers except esp clobbered at this point
10564     # restore ed
10565     89/<- %edx 4/r32/esp
10566     (flush _test-output-buffered-file)
10567     (flush _test-error-buffered-file)
10568 #?     # dump _test-error-stream {{{
10569 #?     (write 2 "^")
10570 #?     (write-stream 2 _test-error-stream)
10571 #?     (write 2 "$\n")
10572 #?     (rewind-stream _test-error-stream)
10573 #?     # }}}
10574     # check output
10575     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-4: output should be empty")
10576     (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")
10577     # check that stop(1) was called
10578     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-4: exit status")
10579     # don't restore from ebp
10580     81 0/subop/add %esp 8/imm32
10581     # . epilogue
10582     5d/pop-to-ebp
10583     c3/return
10585 test-get-with-wrong-output-type-5:
10586     # . prologue
10587     55/push-ebp
10588     89/<- %ebp 4/r32/esp
10589     # setup
10590     (clear-stream _test-input-stream)
10591     (clear-stream $_test-input-buffered-file->buffer)
10592     (clear-stream _test-output-stream)
10593     (clear-stream $_test-output-buffered-file->buffer)
10594     #
10595     (write _test-input-stream "fn foo {\n")
10596     (write _test-input-stream "  var a: t\n")
10597     (write _test-input-stream "  var c/ecx: (addr handle int) <- get a, x\n")
10598     (write _test-input-stream "}\n")
10599     (write _test-input-stream "type t {\n")
10600     (write _test-input-stream "  x: (handle int)\n")
10601     (write _test-input-stream "}\n")
10602     # convert
10603     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
10604     (flush _test-output-buffered-file)
10605     # no errors
10606     # . epilogue
10607     89/<- %esp 5/r32/ebp
10608     5d/pop-to-ebp
10609     c3/return
10611 test-get-with-too-few-inouts:
10612     # . prologue
10613     55/push-ebp
10614     89/<- %ebp 4/r32/esp
10615     # setup
10616     (clear-stream _test-input-stream)
10617     (clear-stream $_test-input-buffered-file->buffer)
10618     (clear-stream _test-output-stream)
10619     (clear-stream $_test-output-buffered-file->buffer)
10620     (clear-stream _test-error-stream)
10621     (clear-stream $_test-error-buffered-file->buffer)
10622     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
10623     68/push 0/imm32
10624     68/push 0/imm32
10625     89/<- %edx 4/r32/esp
10626     (tailor-exit-descriptor %edx 0x10)
10627     #
10628     (write _test-input-stream "fn foo {\n")
10629     (write _test-input-stream "  var a: t\n")
10630     (write _test-input-stream "  var c/ecx: (addr int) <- get a\n")
10631     (write _test-input-stream "}\n")
10632     (write _test-input-stream "type t {\n")
10633     (write _test-input-stream "  x: int\n")
10634     (write _test-input-stream "}\n")
10635     # convert
10636     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
10637     # registers except esp clobbered at this point
10638     # restore ed
10639     89/<- %edx 4/r32/esp
10640     (flush _test-output-buffered-file)
10641     (flush _test-error-buffered-file)
10642 #?     # dump _test-error-stream {{{
10643 #?     (write 2 "^")
10644 #?     (write-stream 2 _test-error-stream)
10645 #?     (write 2 "$\n")
10646 #?     (rewind-stream _test-error-stream)
10647 #?     # }}}
10648     # check output
10649     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-few-inouts: output should be empty")
10650     (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")
10651     # check that stop(1) was called
10652     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-few-inouts: exit status")
10653     # don't restore from ebp
10654     81 0/subop/add %esp 8/imm32
10655     # . epilogue
10656     5d/pop-to-ebp
10657     c3/return
10659 test-get-with-too-many-inouts:
10660     # . prologue
10661     55/push-ebp
10662     89/<- %ebp 4/r32/esp
10663     # setup
10664     (clear-stream _test-input-stream)
10665     (clear-stream $_test-input-buffered-file->buffer)
10666     (clear-stream _test-output-stream)
10667     (clear-stream $_test-output-buffered-file->buffer)
10668     (clear-stream _test-error-stream)
10669     (clear-stream $_test-error-buffered-file->buffer)
10670     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
10671     68/push 0/imm32
10672     68/push 0/imm32
10673     89/<- %edx 4/r32/esp
10674     (tailor-exit-descriptor %edx 0x10)
10675     #
10676     (write _test-input-stream "fn foo {\n")
10677     (write _test-input-stream "  var a: t\n")
10678     (write _test-input-stream "  var c/ecx: (addr int) <- get a, x, 0\n")
10679     (write _test-input-stream "}\n")
10680     (write _test-input-stream "type t {\n")
10681     (write _test-input-stream "  x: int\n")
10682     (write _test-input-stream "}\n")
10683     # convert
10684     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
10685     # registers except esp clobbered at this point
10686     # restore ed
10687     89/<- %edx 4/r32/esp
10688     (flush _test-output-buffered-file)
10689     (flush _test-error-buffered-file)
10690 #?     # dump _test-error-stream {{{
10691 #?     (write 2 "^")
10692 #?     (write-stream 2 _test-error-stream)
10693 #?     (write 2 "$\n")
10694 #?     (rewind-stream _test-error-stream)
10695 #?     # }}}
10696     # check output
10697     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-many-inouts: output should be empty")
10698     (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")
10699     # check that stop(1) was called
10700     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-many-inouts: exit status")
10701     # don't restore from ebp
10702     81 0/subop/add %esp 8/imm32
10703     # . epilogue
10704     5d/pop-to-ebp
10705     c3/return
10707 test-get-with-no-output:
10708     # . prologue
10709     55/push-ebp
10710     89/<- %ebp 4/r32/esp
10711     # setup
10712     (clear-stream _test-input-stream)
10713     (clear-stream $_test-input-buffered-file->buffer)
10714     (clear-stream _test-output-stream)
10715     (clear-stream $_test-output-buffered-file->buffer)
10716     (clear-stream _test-error-stream)
10717     (clear-stream $_test-error-buffered-file->buffer)
10718     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
10719     68/push 0/imm32
10720     68/push 0/imm32
10721     89/<- %edx 4/r32/esp
10722     (tailor-exit-descriptor %edx 0x10)
10723     #
10724     (write _test-input-stream "fn foo {\n")
10725     (write _test-input-stream "  var a: t\n")
10726     (write _test-input-stream "  get a, x\n")
10727     (write _test-input-stream "}\n")
10728     (write _test-input-stream "type t {\n")
10729     (write _test-input-stream "  x: int\n")
10730     (write _test-input-stream "}\n")
10731     # convert
10732     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
10733     # registers except esp clobbered at this point
10734     # restore ed
10735     89/<- %edx 4/r32/esp
10736     (flush _test-output-buffered-file)
10737     (flush _test-error-buffered-file)
10738 #?     # dump _test-error-stream {{{
10739 #?     (write 2 "^")
10740 #?     (write-stream 2 _test-error-stream)
10741 #?     (write 2 "$\n")
10742 #?     (rewind-stream _test-error-stream)
10743 #?     # }}}
10744     # check output
10745     (check-stream-equal _test-output-stream  ""  "F - test-get-with-no-output: output should be empty")
10746     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: must have an output"  "F - test-get-with-no-output: error message")
10747     # check that stop(1) was called
10748     (check-ints-equal *(edx+4) 2 "F - test-get-with-no-output: exit status")
10749     # don't restore from ebp
10750     81 0/subop/add %esp 8/imm32
10751     # . epilogue
10752     5d/pop-to-ebp
10753     c3/return
10755 test-get-with-too-many-outputs:
10756     # . prologue
10757     55/push-ebp
10758     89/<- %ebp 4/r32/esp
10759     # setup
10760     (clear-stream _test-input-stream)
10761     (clear-stream $_test-input-buffered-file->buffer)
10762     (clear-stream _test-output-stream)
10763     (clear-stream $_test-output-buffered-file->buffer)
10764     (clear-stream _test-error-stream)
10765     (clear-stream $_test-error-buffered-file->buffer)
10766     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
10767     68/push 0/imm32
10768     68/push 0/imm32
10769     89/<- %edx 4/r32/esp
10770     (tailor-exit-descriptor %edx 0x10)
10771     #
10772     (write _test-input-stream "fn foo {\n")
10773     (write _test-input-stream "  var a: t\n")
10774     (write _test-input-stream "  var b: int\n")
10775     (write _test-input-stream "  var c/eax: (addr int) <- copy 0\n")
10776     (write _test-input-stream "  c, b <- get a, x\n")
10777     (write _test-input-stream "}\n")
10778     (write _test-input-stream "type t {\n")
10779     (write _test-input-stream "  x: int\n")
10780     (write _test-input-stream "}\n")
10781     # convert
10782     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
10783     # registers except esp clobbered at this point
10784     # restore ed
10785     89/<- %edx 4/r32/esp
10786     (flush _test-output-buffered-file)
10787     (flush _test-error-buffered-file)
10788 #?     # dump _test-error-stream {{{
10789 #?     (write 2 "^")
10790 #?     (write-stream 2 _test-error-stream)
10791 #?     (write 2 "$\n")
10792 #?     (rewind-stream _test-error-stream)
10793 #?     # }}}
10794     # check output
10795     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-many-outputs: output should be empty")
10796     (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")
10797     # check that stop(1) was called
10798     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-many-outputs: exit status")
10799     # don't restore from ebp
10800     81 0/subop/add %esp 8/imm32
10801     # . epilogue
10802     5d/pop-to-ebp
10803     c3/return
10805 test-convert-array-of-user-defined-types:
10806     # . prologue
10807     55/push-ebp
10808     89/<- %ebp 4/r32/esp
10809     # setup
10810     (clear-stream _test-input-stream)
10811     (clear-stream $_test-input-buffered-file->buffer)
10812     (clear-stream _test-output-stream)
10813     (clear-stream $_test-output-buffered-file->buffer)
10814     #
10815     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
10816     (write _test-input-stream "  x: int\n")
10817     (write _test-input-stream "  y: int\n")
10818     (write _test-input-stream "}\n")
10819     (write _test-input-stream "fn foo {\n")
10820     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
10821     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
10822     (write _test-input-stream "  var x/eax: (addr t) <- index arr, idx\n")
10823     (write _test-input-stream "}\n")
10824     # convert
10825     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
10826     (flush _test-output-buffered-file)
10827 #?     # dump _test-output-stream {{{
10828 #?     (write 2 "^")
10829 #?     (write-stream 2 _test-output-stream)
10830 #?     (write 2 "$\n")
10831 #?     (rewind-stream _test-output-stream)
10832 #?     # }}}
10833     # check output
10834     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-array-of-user-defined-types/0")
10835     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-array-of-user-defined-types/1")
10836     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-array-of-user-defined-types/2")
10837     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-array-of-user-defined-types/3")
10838     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-array-of-user-defined-types/4")
10839     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-array-of-user-defined-types/5")
10840     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-array-of-user-defined-types/6")
10841     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-array-of-user-defined-types/7")
10842     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-array-of-user-defined-types/8")
10843     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-array-of-user-defined-types/9")
10844     (check-next-stream-line-equal _test-output-stream "    (__check-mu-array-bounds %ecx 0x00000008 *eax \"foo\" \"arr\")"  "F - test-convert-array-of-user-defined-types/10")
10845     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %eax 0/imm32"  "F - test-convert-array-of-user-defined-types/12")
10846     (check-next-stream-line-equal _test-output-stream "    0f 84/jump-if-= __mu-abort-null-index-base-address/disp32"  "F - test-convert-array-of-user-defined-types/13")
10847     (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/14")
10848     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-array-of-user-defined-types/15")
10849     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-array-of-user-defined-types/16")
10850     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-array-of-user-defined-types/17")
10851     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-array-of-user-defined-types/18")
10852     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-array-of-user-defined-types/19")
10853     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-array-of-user-defined-types/20")
10854     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-array-of-user-defined-types/21")
10855     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-array-of-user-defined-types/22")
10856     # . epilogue
10857     89/<- %esp 5/r32/ebp
10858     5d/pop-to-ebp
10859     c3/return
10861 test-convert-length-of-array-of-user-defined-types-to-eax:
10862     # . prologue
10863     55/push-ebp
10864     89/<- %ebp 4/r32/esp
10865     # setup
10866     (clear-stream _test-input-stream)
10867     (clear-stream $_test-input-buffered-file->buffer)
10868     (clear-stream _test-output-stream)
10869     (clear-stream $_test-output-buffered-file->buffer)
10870     #
10871     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
10872     (write _test-input-stream "  x: int\n")
10873     (write _test-input-stream "  y: int\n")
10874     (write _test-input-stream "  z: int\n")
10875     (write _test-input-stream "}\n")
10876     (write _test-input-stream "fn foo {\n")
10877     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
10878     (write _test-input-stream "  var x/eax: int <- length arr\n")
10879     (write _test-input-stream "}\n")
10880     # convert
10881     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
10882     (flush _test-output-buffered-file)
10883 #?     # dump _test-output-stream {{{
10884 #?     (write 2 "^")
10885 #?     (write-stream 2 _test-output-stream)
10886 #?     (write 2 "$\n")
10887 #?     (rewind-stream _test-output-stream)
10888 #?     # }}}
10889     # check output
10890     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-eax/0")
10891     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/1")
10892     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-eax/2")
10893     (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")
10894     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/4")
10895     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-eax/5")
10896     # var arr
10897     (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")
10898     (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")
10899     # length instruction
10900     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/8")
10901     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/9")
10902     (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")
10903     (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")
10904     (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")
10905     (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")
10906     (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")
10907     (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")
10908     # reclaim arr
10909     (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")
10910     #
10911     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/17")
10912     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/18")
10913     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/19")
10914     (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")
10915     (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")
10916     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-eax/22")
10917     # . epilogue
10918     89/<- %esp 5/r32/ebp
10919     5d/pop-to-ebp
10920     c3/return
10922 test-convert-length-of-array-of-user-defined-types-to-ecx:
10923     # . prologue
10924     55/push-ebp
10925     89/<- %ebp 4/r32/esp
10926     # setup
10927     (clear-stream _test-input-stream)
10928     (clear-stream $_test-input-buffered-file->buffer)
10929     (clear-stream _test-output-stream)
10930     (clear-stream $_test-output-buffered-file->buffer)
10931     #
10932     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
10933     (write _test-input-stream "  x: int\n")
10934     (write _test-input-stream "  y: int\n")
10935     (write _test-input-stream "  z: int\n")
10936     (write _test-input-stream "}\n")
10937     (write _test-input-stream "fn foo {\n")
10938     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
10939     (write _test-input-stream "  var x/ecx: int <- length arr\n")
10940     (write _test-input-stream "}\n")
10941     # convert
10942     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
10943     (flush _test-output-buffered-file)
10944 #?     # dump _test-output-stream {{{
10945 #?     (write 2 "^")
10946 #?     (write-stream 2 _test-output-stream)
10947 #?     (write 2 "$\n")
10948 #?     (rewind-stream _test-output-stream)
10949 #?     # }}}
10950     # check output
10951     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-ecx/0")
10952     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/1")
10953     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-ecx/2")
10954     (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")
10955     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/4")
10956     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-ecx/5")
10957     # var a
10958     (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")
10959     (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")
10960     # var x
10961     (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")
10962     # length instruction
10963     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/9")
10964     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/10")
10965     (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")
10966     (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")
10967     (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")
10968     (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")
10969     (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")
10970     (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")
10971     (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")
10972     # reclaim x
10973     (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")
10974     # reclaim a
10975     (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")
10976     #
10977     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/20")
10978     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/21")
10979     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/22")
10980     (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")
10981     (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")
10982     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-ecx/25")
10983     # . epilogue
10984     89/<- %esp 5/r32/ebp
10985     5d/pop-to-ebp
10986     c3/return
10988 test-convert-length-of-array-of-user-defined-types-to-edx:
10989     # . prologue
10990     55/push-ebp
10991     89/<- %ebp 4/r32/esp
10992     # setup
10993     (clear-stream _test-input-stream)
10994     (clear-stream $_test-input-buffered-file->buffer)
10995     (clear-stream _test-output-stream)
10996     (clear-stream $_test-output-buffered-file->buffer)
10997     #
10998     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
10999     (write _test-input-stream "  x: int\n")
11000     (write _test-input-stream "  y: int\n")
11001     (write _test-input-stream "  z: int\n")
11002     (write _test-input-stream "}\n")
11003     (write _test-input-stream "fn foo {\n")
11004     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
11005     (write _test-input-stream "  var x/edx: int <- length arr\n")
11006     (write _test-input-stream "}\n")
11007     # convert
11008     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
11009     (flush _test-output-buffered-file)
11010 #?     # dump _test-output-stream {{{
11011 #?     (write 2 "^")
11012 #?     (write-stream 2 _test-output-stream)
11013 #?     (write 2 "$\n")
11014 #?     (rewind-stream _test-output-stream)
11015 #?     # }}}
11016     # check output
11017     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-edx/0")
11018     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/1")
11019     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-edx/2")
11020     (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")
11021     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/4")
11022     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-edx/5")
11023     # var a
11024     (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")
11025     (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")
11026     # var x
11027     (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")
11028     # length instruction
11029     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/9")
11030     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/10")
11031     (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")
11032     (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")
11033     (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")
11034     (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")
11035     (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")
11036     (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")
11037     (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")
11038     # reclaim x
11039     (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")
11040     # reclaim a
11041     (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")
11042     #
11043     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/20")
11044     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/21")
11045     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/22")
11046     (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")
11047     (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")
11048     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-edx/25")
11049     # . epilogue
11050     89/<- %esp 5/r32/ebp
11051     5d/pop-to-ebp
11052     c3/return
11054 test-convert-length-of-array-of-user-defined-types:
11055     # . prologue
11056     55/push-ebp
11057     89/<- %ebp 4/r32/esp
11058     # setup
11059     (clear-stream _test-input-stream)
11060     (clear-stream $_test-input-buffered-file->buffer)
11061     (clear-stream _test-output-stream)
11062     (clear-stream $_test-output-buffered-file->buffer)
11063     #
11064     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
11065     (write _test-input-stream "  x: int\n")
11066     (write _test-input-stream "  y: int\n")
11067     (write _test-input-stream "  z: int\n")
11068     (write _test-input-stream "}\n")
11069     (write _test-input-stream "fn foo {\n")
11070     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
11071     (write _test-input-stream "  var x/ebx: int <- length arr\n")
11072     (write _test-input-stream "}\n")
11073     # convert
11074     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
11075     (flush _test-output-buffered-file)
11076 #?     # dump _test-output-stream {{{
11077 #?     (write 2 "^")
11078 #?     (write-stream 2 _test-output-stream)
11079 #?     (write 2 "$\n")
11080 #?     (rewind-stream _test-output-stream)
11081 #?     # }}}
11082     # check output
11083     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types/0")
11084     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types/1")
11085     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types/2")
11086     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-user-defined-types/3")
11087     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types/4")
11088     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types/5")
11089     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-user-defined-types/6")
11090     (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")
11091     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ebx"  "F - test-convert-length-of-array-of-user-defined-types/8")
11092     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types/9")
11093     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types/10")
11094     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types/11")
11095     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-user-defined-types/12")
11096     (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")
11097     (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")
11098     (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")
11099     (check-next-stream-line-equal _test-output-stream "    89/<- %ebx 0/r32/eax"  "F - test-convert-length-of-array-of-user-defined-types/16")
11100     (check-next-stream-line-equal _test-output-stream "    5a/pop-to-edx"       "F - test-convert-length-of-array-of-user-defined-types/17")
11101     (check-next-stream-line-equal _test-output-stream "    59/pop-to-ecx"       "F - test-convert-length-of-array-of-user-defined-types/18")
11102     (check-next-stream-line-equal _test-output-stream "    58/pop-to-eax"       "F - test-convert-length-of-array-of-user-defined-types/19")
11103     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ebx"  "F - test-convert-length-of-array-of-user-defined-types/20")
11104     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-user-defined-types/21")
11105     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types/22")
11106     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types/23")
11107     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types/24")
11108     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-user-defined-types/25")
11109     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-user-defined-types/26")
11110     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types/27")
11111     # . epilogue
11112     89/<- %esp 5/r32/ebp
11113     5d/pop-to-ebp
11114     c3/return
11116 test-index-with-non-array-atom-base-type:
11117     # . prologue
11118     55/push-ebp
11119     89/<- %ebp 4/r32/esp
11120     # setup
11121     (clear-stream _test-input-stream)
11122     (clear-stream $_test-input-buffered-file->buffer)
11123     (clear-stream _test-output-stream)
11124     (clear-stream $_test-output-buffered-file->buffer)
11125     (clear-stream _test-error-stream)
11126     (clear-stream $_test-error-buffered-file->buffer)
11127     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
11128     68/push 0/imm32
11129     68/push 0/imm32
11130     89/<- %edx 4/r32/esp
11131     (tailor-exit-descriptor %edx 0x10)
11132     #
11133     (write _test-input-stream "fn foo {\n")
11134     (write _test-input-stream "  var a: int\n")
11135     (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
11136     (write _test-input-stream "}\n")
11137     # convert
11138     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
11139     # registers except esp clobbered at this point
11140     # restore ed
11141     89/<- %edx 4/r32/esp
11142     (flush _test-output-buffered-file)
11143     (flush _test-error-buffered-file)
11144 #?     # dump _test-error-stream {{{
11145 #?     (write 2 "^")
11146 #?     (write-stream 2 _test-error-stream)
11147 #?     (write 2 "$\n")
11148 #?     (rewind-stream _test-error-stream)
11149 #?     # }}}
11150     # check output
11151     (check-stream-equal _test-output-stream  ""  "F - test-index-with-non-array-atom-base-type: output should be empty")
11152     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: var 'a' is not an array"  "F - test-index-with-non-array-atom-base-type: error message")
11153     # check that stop(1) was called
11154     (check-ints-equal *(edx+4) 2 "F - test-index-with-non-array-atom-base-type: exit status")
11155     # don't restore from ebp
11156     81 0/subop/add %esp 8/imm32
11157     # . epilogue
11158     5d/pop-to-ebp
11159     c3/return
11161 test-index-with-non-array-compound-base-type:
11162     # . prologue
11163     55/push-ebp
11164     89/<- %ebp 4/r32/esp
11165     # setup
11166     (clear-stream _test-input-stream)
11167     (clear-stream $_test-input-buffered-file->buffer)
11168     (clear-stream _test-output-stream)
11169     (clear-stream $_test-output-buffered-file->buffer)
11170     (clear-stream _test-error-stream)
11171     (clear-stream $_test-error-buffered-file->buffer)
11172     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
11173     68/push 0/imm32
11174     68/push 0/imm32
11175     89/<- %edx 4/r32/esp
11176     (tailor-exit-descriptor %edx 0x10)
11177     #
11178     (write _test-input-stream "fn foo {\n")
11179     (write _test-input-stream "  var a: (handle int)\n")
11180     (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
11181     (write _test-input-stream "}\n")
11182     # convert
11183     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
11184     # registers except esp clobbered at this point
11185     # restore ed
11186     89/<- %edx 4/r32/esp
11187     (flush _test-output-buffered-file)
11188     (flush _test-error-buffered-file)
11189 #?     # dump _test-error-stream {{{
11190 #?     (write 2 "^")
11191 #?     (write-stream 2 _test-error-stream)
11192 #?     (write 2 "$\n")
11193 #?     (rewind-stream _test-error-stream)
11194 #?     # }}}
11195     # check output
11196     (check-stream-equal _test-output-stream  ""  "F - test-index-with-non-array-compound-base-type: output should be empty")
11197     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: var 'a' is not an array"  "F - test-index-with-non-array-compound-base-type: error message")
11198     # check that stop(1) was called
11199     (check-ints-equal *(edx+4) 2 "F - test-index-with-non-array-compound-base-type: exit status")
11200     # don't restore from ebp
11201     81 0/subop/add %esp 8/imm32
11202     # . epilogue
11203     5d/pop-to-ebp
11204     c3/return
11206 test-index-with-non-array-compound-base-type-2:
11207     # . prologue
11208     55/push-ebp
11209     89/<- %ebp 4/r32/esp
11210     # setup
11211     (clear-stream _test-input-stream)
11212     (clear-stream $_test-input-buffered-file->buffer)
11213     (clear-stream _test-output-stream)
11214     (clear-stream $_test-output-buffered-file->buffer)
11215     (clear-stream _test-error-stream)
11216     (clear-stream $_test-error-buffered-file->buffer)
11217     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
11218     68/push 0/imm32
11219     68/push 0/imm32
11220     89/<- %edx 4/r32/esp
11221     (tailor-exit-descriptor %edx 0x10)
11222     #
11223     (write _test-input-stream "fn foo {\n")
11224     (write _test-input-stream "  var a: (addr int)\n")
11225     (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
11226     (write _test-input-stream "}\n")
11227     # convert
11228     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
11229     # registers except esp clobbered at this point
11230     # restore ed
11231     89/<- %edx 4/r32/esp
11232     (flush _test-output-buffered-file)
11233     (flush _test-error-buffered-file)
11234 #?     # dump _test-error-stream {{{
11235 #?     (write 2 "^")
11236 #?     (write-stream 2 _test-error-stream)
11237 #?     (write 2 "$\n")
11238 #?     (rewind-stream _test-error-stream)
11239 #?     # }}}
11240     # check output
11241     (check-stream-equal _test-output-stream  ""  "F - test-index-with-non-array-compound-base-type-2: output should be empty")
11242     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: var 'a' is not an array"  "F - test-index-with-non-array-compound-base-type-2: error message")
11243     # check that stop(1) was called
11244     (check-ints-equal *(edx+4) 2 "F - test-index-with-non-array-compound-base-type-2: exit status")
11245     # don't restore from ebp
11246     81 0/subop/add %esp 8/imm32
11247     # . epilogue
11248     5d/pop-to-ebp
11249     c3/return
11251 test-index-with-array-atom-base-type:
11252     # . prologue
11253     55/push-ebp
11254     89/<- %ebp 4/r32/esp
11255     # setup
11256     (clear-stream _test-input-stream)
11257     (clear-stream $_test-input-buffered-file->buffer)
11258     (clear-stream _test-output-stream)
11259     (clear-stream $_test-output-buffered-file->buffer)
11260     (clear-stream _test-error-stream)
11261     (clear-stream $_test-error-buffered-file->buffer)
11262     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
11263     68/push 0/imm32
11264     68/push 0/imm32
11265     89/<- %edx 4/r32/esp
11266     (tailor-exit-descriptor %edx 0x10)
11267     #
11268     (write _test-input-stream "fn foo {\n")
11269     (write _test-input-stream "  var a: array\n")
11270     (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
11271     (write _test-input-stream "}\n")
11272     # convert
11273     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
11274     # registers except esp clobbered at this point
11275     # restore ed
11276     89/<- %edx 4/r32/esp
11277     (flush _test-output-buffered-file)
11278     (flush _test-error-buffered-file)
11279 #?     # dump _test-error-stream {{{
11280 #?     (write 2 "^")
11281 #?     (write-stream 2 _test-error-stream)
11282 #?     (write 2 "$\n")
11283 #?     (rewind-stream _test-error-stream)
11284 #?     # }}}
11285     # check output
11286     (check-stream-equal _test-output-stream  ""  "F - test-index-with-array-atom-base-type: output should be empty")
11287     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: array 'a' must specify the type of its elements"  "F - test-index-with-array-atom-base-type: error message")
11288     # check that stop(1) was called
11289     (check-ints-equal *(edx+4) 2 "F - test-index-with-array-atom-base-type: exit status")
11290     # don't restore from ebp
11291     81 0/subop/add %esp 8/imm32
11292     # . epilogue
11293     5d/pop-to-ebp
11294     c3/return
11296 test-index-with-addr-base-on-stack:
11297     # . prologue
11298     55/push-ebp
11299     89/<- %ebp 4/r32/esp
11300     # setup
11301     (clear-stream _test-input-stream)
11302     (clear-stream $_test-input-buffered-file->buffer)
11303     (clear-stream _test-output-stream)
11304     (clear-stream $_test-output-buffered-file->buffer)
11305     (clear-stream _test-error-stream)
11306     (clear-stream $_test-error-buffered-file->buffer)
11307     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
11308     68/push 0/imm32
11309     68/push 0/imm32
11310     89/<- %edx 4/r32/esp
11311     (tailor-exit-descriptor %edx 0x10)
11312     #
11313     (write _test-input-stream "fn foo {\n")
11314     (write _test-input-stream "  var a: (addr array int)\n")
11315     (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
11316     (write _test-input-stream "}\n")
11317     # convert
11318     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
11319     # registers except esp clobbered at this point
11320     # restore ed
11321     89/<- %edx 4/r32/esp
11322     (flush _test-output-buffered-file)
11323     (flush _test-error-buffered-file)
11324 #?     # dump _test-error-stream {{{
11325 #?     (write 2 "^")
11326 #?     (write-stream 2 _test-error-stream)
11327 #?     (write 2 "$\n")
11328 #?     (rewind-stream _test-error-stream)
11329 #?     # }}}
11330     # check output
11331     (check-stream-equal _test-output-stream  ""  "F - test-index-with-addr-base-on-stack: output should be empty")
11332     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: var 'a' is an addr to an array, and so must live in a register"  "F - test-index-with-addr-base-on-stack: error message")
11333     # check that stop(1) was called
11334     (check-ints-equal *(edx+4) 2 "F - test-index-with-addr-base-on-stack: exit status")
11335     # don't restore from ebp
11336     81 0/subop/add %esp 8/imm32
11337     # . epilogue
11338     5d/pop-to-ebp
11339     c3/return
11341 test-index-with-wrong-index-type:
11342     # . prologue
11343     55/push-ebp
11344     89/<- %ebp 4/r32/esp
11345     # setup
11346     (clear-stream _test-input-stream)
11347     (clear-stream $_test-input-buffered-file->buffer)
11348     (clear-stream _test-output-stream)
11349     (clear-stream $_test-output-buffered-file->buffer)
11350     (clear-stream _test-error-stream)
11351     (clear-stream $_test-error-buffered-file->buffer)
11352     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
11353     68/push 0/imm32
11354     68/push 0/imm32
11355     89/<- %edx 4/r32/esp
11356     (tailor-exit-descriptor %edx 0x10)
11357     #
11358     (write _test-input-stream "fn foo {\n")
11359     (write _test-input-stream "  var a/eax: (addr array int) <- copy 0\n")
11360     (write _test-input-stream "  var b: boolean\n")
11361     (write _test-input-stream "  var c/ecx: (addr int) <- index a, b\n")
11362     (write _test-input-stream "}\n")
11363     # convert
11364     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
11365     # registers except esp clobbered at this point
11366     # restore ed
11367     89/<- %edx 4/r32/esp
11368     (flush _test-output-buffered-file)
11369     (flush _test-error-buffered-file)
11370 #?     # dump _test-error-stream {{{
11371 #?     (write 2 "^")
11372 #?     (write-stream 2 _test-error-stream)
11373 #?     (write 2 "$\n")
11374 #?     (rewind-stream _test-error-stream)
11375 #?     # }}}
11376     # check output
11377     (check-stream-equal _test-output-stream  ""  "F - test-index-with-wrong-index-type: output should be empty")
11378     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: second argument 'b' must be an int or offset"  "F - test-index-with-wrong-index-type: error message")
11379     # check that stop(1) was called
11380     (check-ints-equal *(edx+4) 2 "F - test-index-with-wrong-index-type: exit status")
11381     # don't restore from ebp
11382     81 0/subop/add %esp 8/imm32
11383     # . epilogue
11384     5d/pop-to-ebp
11385     c3/return
11387 test-index-with-offset-atom-index-type:
11388     # . prologue
11389     55/push-ebp
11390     89/<- %ebp 4/r32/esp
11391     # setup
11392     (clear-stream _test-input-stream)
11393     (clear-stream $_test-input-buffered-file->buffer)
11394     (clear-stream _test-output-stream)
11395     (clear-stream $_test-output-buffered-file->buffer)
11396     (clear-stream _test-error-stream)
11397     (clear-stream $_test-error-buffered-file->buffer)
11398     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
11399     68/push 0/imm32
11400     68/push 0/imm32
11401     89/<- %edx 4/r32/esp
11402     (tailor-exit-descriptor %edx 0x10)
11403     #
11404     (write _test-input-stream "fn foo {\n")
11405     (write _test-input-stream "  var a/eax: (addr array int) <- copy 0\n")
11406     (write _test-input-stream "  var b: offset\n")
11407     (write _test-input-stream "  var c/ecx: (addr int) <- index a, b\n")
11408     (write _test-input-stream "}\n")
11409     # convert
11410     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
11411     # registers except esp clobbered at this point
11412     # restore ed
11413     89/<- %edx 4/r32/esp
11414     (flush _test-output-buffered-file)
11415     (flush _test-error-buffered-file)
11416 #?     # dump _test-error-stream {{{
11417 #?     (write 2 "^")
11418 #?     (write-stream 2 _test-error-stream)
11419 #?     (write 2 "$\n")
11420 #?     (rewind-stream _test-error-stream)
11421 #?     # }}}
11422     # check output
11423     (check-stream-equal _test-output-stream  ""  "F - test-index-with-offset-atom-index-type: output should be empty")
11424     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: offset 'b' must specify the type of array elements"  "F - test-index-with-offset-atom-index-type: error message")
11425     # check that stop(1) was called
11426     (check-ints-equal *(edx+4) 2 "F - test-index-with-offset-atom-index-type: exit status")
11427     # don't restore from ebp
11428     81 0/subop/add %esp 8/imm32
11429     # . epilogue
11430     5d/pop-to-ebp
11431     c3/return
11433 test-index-with-offset-on-stack:
11434     # . prologue
11435     55/push-ebp
11436     89/<- %ebp 4/r32/esp
11437     # setup
11438     (clear-stream _test-input-stream)
11439     (clear-stream $_test-input-buffered-file->buffer)
11440     (clear-stream _test-output-stream)
11441     (clear-stream $_test-output-buffered-file->buffer)
11442     (clear-stream _test-error-stream)
11443     (clear-stream $_test-error-buffered-file->buffer)
11444     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
11445     68/push 0/imm32
11446     68/push 0/imm32
11447     89/<- %edx 4/r32/esp
11448     (tailor-exit-descriptor %edx 0x10)
11449     #
11450     (write _test-input-stream "fn foo {\n")
11451     (write _test-input-stream "  var a/eax: (addr array int) <- copy 0\n")
11452     (write _test-input-stream "  var b: int\n")
11453     (write _test-input-stream "  var c/ecx: (addr int) <- index a, b\n")
11454     (write _test-input-stream "}\n")
11455     # convert
11456     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
11457     # registers except esp clobbered at this point
11458     # restore ed
11459     89/<- %edx 4/r32/esp
11460     (flush _test-output-buffered-file)
11461     (flush _test-error-buffered-file)
11462 #?     # dump _test-error-stream {{{
11463 #?     (write 2 "^")
11464 #?     (write-stream 2 _test-error-stream)
11465 #?     (write 2 "$\n")
11466 #?     (rewind-stream _test-error-stream)
11467 #?     # }}}
11468     # check output
11469     (check-stream-equal _test-output-stream  ""  "F - test-index-with-offset-on-stack: output should be empty")
11470     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: second argument 'b' must be in a register"  "F - test-index-with-offset-on-stack: error message")
11471     # check that stop(1) was called
11472     (check-ints-equal *(edx+4) 2 "F - test-index-with-offset-on-stack: exit status")
11473     # don't restore from ebp
11474     81 0/subop/add %esp 8/imm32
11475     # . epilogue
11476     5d/pop-to-ebp
11477     c3/return
11479 test-index-needs-offset-type:
11480     # . prologue
11481     55/push-ebp
11482     89/<- %ebp 4/r32/esp
11483     # setup
11484     (clear-stream _test-input-stream)
11485     (clear-stream $_test-input-buffered-file->buffer)
11486     (clear-stream _test-output-stream)
11487     (clear-stream $_test-output-buffered-file->buffer)
11488     (clear-stream _test-error-stream)
11489     (clear-stream $_test-error-buffered-file->buffer)
11490     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
11491     68/push 0/imm32
11492     68/push 0/imm32
11493     89/<- %edx 4/r32/esp
11494     (tailor-exit-descriptor %edx 0x10)
11495     #
11496     (write _test-input-stream "fn foo {\n")
11497     (write _test-input-stream "  var a/eax: (addr array t) <- copy 0\n")
11498     (write _test-input-stream "  var b/ebx: int <- copy 0\n")
11499     (write _test-input-stream "  var c/ecx: (addr int) <- index a, b\n")
11500     (write _test-input-stream "}\n")
11501     (write _test-input-stream "type t {\n")  # size 12 is not a power of two
11502     (write _test-input-stream "  x: int\n")
11503     (write _test-input-stream "  y: int\n")
11504     (write _test-input-stream "  z: int\n")
11505     (write _test-input-stream "}\n")
11506     # convert
11507     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
11508     # registers except esp clobbered at this point
11509     # restore ed
11510     89/<- %edx 4/r32/esp
11511     (flush _test-output-buffered-file)
11512     (flush _test-error-buffered-file)
11513 #?     # dump _test-error-stream {{{
11514 #?     (write 2 "^")
11515 #?     (write-stream 2 _test-error-stream)
11516 #?     (write 2 "$\n")
11517 #?     (rewind-stream _test-error-stream)
11518 #?     # }}}
11519     # check output
11520     (check-stream-equal _test-output-stream  ""  "F - test-index-needs-offset-type: output should be empty")
11521     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: cannot take an int for array 'a'; create an offset instead. See mu.md for details."  "F - test-index-needs-offset-type: error message")
11522     # check that stop(1) was called
11523     (check-ints-equal *(edx+4) 2 "F - test-index-needs-offset-type: exit status")
11524     # don't restore from ebp
11525     81 0/subop/add %esp 8/imm32
11526     # . epilogue
11527     5d/pop-to-ebp
11528     c3/return
11530 test-index-with-output-not-address:
11531     # . prologue
11532     55/push-ebp
11533     89/<- %ebp 4/r32/esp
11534     # setup
11535     (clear-stream _test-input-stream)
11536     (clear-stream $_test-input-buffered-file->buffer)
11537     (clear-stream _test-output-stream)
11538     (clear-stream $_test-output-buffered-file->buffer)
11539     (clear-stream _test-error-stream)
11540     (clear-stream $_test-error-buffered-file->buffer)
11541     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
11542     68/push 0/imm32
11543     68/push 0/imm32
11544     89/<- %edx 4/r32/esp
11545     (tailor-exit-descriptor %edx 0x10)
11546     #
11547     (write _test-input-stream "fn foo {\n")
11548     (write _test-input-stream "  var a/ebx: (addr array boolean) <- copy 0\n")
11549     (write _test-input-stream "  var o/edi: int <- index a, 0\n")
11550     (write _test-input-stream "}\n")
11551     # convert
11552     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
11553     # registers except esp clobbered at this point
11554     # restore ed
11555     89/<- %edx 4/r32/esp
11556     (flush _test-output-buffered-file)
11557     (flush _test-error-buffered-file)
11558 #?     # dump _test-error-stream {{{
11559 #?     (write 2 "^")
11560 #?     (write-stream 2 _test-error-stream)
11561 #?     (write 2 "$\n")
11562 #?     (rewind-stream _test-error-stream)
11563 #?     # }}}
11564     # check output
11565     (check-stream-equal _test-output-stream  ""  "F - test-index-with-output-not-address: output should be empty")
11566     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: output 'o' must be an addr"  "F - test-index-with-output-not-address: error message")
11567     # check that stop(1) was called
11568     (check-ints-equal *(edx+4) 2 "F - test-index-with-output-not-address: exit status")
11569     # don't restore from ebp
11570     81 0/subop/add %esp 8/imm32
11571     # . epilogue
11572     5d/pop-to-ebp
11573     c3/return
11575 test-index-with-output-not-address-2:
11576     # . prologue
11577     55/push-ebp
11578     89/<- %ebp 4/r32/esp
11579     # setup
11580     (clear-stream _test-input-stream)
11581     (clear-stream $_test-input-buffered-file->buffer)
11582     (clear-stream _test-output-stream)
11583     (clear-stream $_test-output-buffered-file->buffer)
11584     (clear-stream _test-error-stream)
11585     (clear-stream $_test-error-buffered-file->buffer)
11586     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
11587     68/push 0/imm32
11588     68/push 0/imm32
11589     89/<- %edx 4/r32/esp
11590     (tailor-exit-descriptor %edx 0x10)
11591     #
11592     (write _test-input-stream "fn foo {\n")
11593     (write _test-input-stream "  var a/ebx: (addr array boolean) <- copy 0\n")
11594     (write _test-input-stream "  var o/edi: (int) <- index a, 0\n")
11595     (write _test-input-stream "}\n")
11596     # convert
11597     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
11598     # registers except esp clobbered at this point
11599     # restore ed
11600     89/<- %edx 4/r32/esp
11601     (flush _test-output-buffered-file)
11602     (flush _test-error-buffered-file)
11603 #?     # dump _test-error-stream {{{
11604 #?     (write 2 "^")
11605 #?     (write-stream 2 _test-error-stream)
11606 #?     (write 2 "$\n")
11607 #?     (rewind-stream _test-error-stream)
11608 #?     # }}}
11609     # check output
11610     (check-stream-equal _test-output-stream  ""  "F - test-index-with-output-not-address-2: output should be empty")
11611     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: output 'o' must be an addr"  "F - test-index-with-output-not-address-2: error message")
11612     # check that stop(1) was called
11613     (check-ints-equal *(edx+4) 2 "F - test-index-with-output-not-address-2: exit status")
11614     # don't restore from ebp
11615     81 0/subop/add %esp 8/imm32
11616     # . epilogue
11617     5d/pop-to-ebp
11618     c3/return
11620 test-index-with-wrong-output-type:
11621     # . prologue
11622     55/push-ebp
11623     89/<- %ebp 4/r32/esp
11624     # setup
11625     (clear-stream _test-input-stream)
11626     (clear-stream $_test-input-buffered-file->buffer)
11627     (clear-stream _test-output-stream)
11628     (clear-stream $_test-output-buffered-file->buffer)
11629     (clear-stream _test-error-stream)
11630     (clear-stream $_test-error-buffered-file->buffer)
11631     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
11632     68/push 0/imm32
11633     68/push 0/imm32
11634     89/<- %edx 4/r32/esp
11635     (tailor-exit-descriptor %edx 0x10)
11636     #
11637     (write _test-input-stream "fn foo {\n")
11638     (write _test-input-stream "  var a/ebx: (addr array boolean) <- copy 0\n")
11639     (write _test-input-stream "  var o/edi: (addr int) <- index a, 0\n")
11640     (write _test-input-stream "}\n")
11641     # convert
11642     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
11643     # registers except esp clobbered at this point
11644     # restore ed
11645     89/<- %edx 4/r32/esp
11646     (flush _test-output-buffered-file)
11647     (flush _test-error-buffered-file)
11648 #?     # dump _test-error-stream {{{
11649 #?     (write 2 "^")
11650 #?     (write-stream 2 _test-error-stream)
11651 #?     (write 2 "$\n")
11652 #?     (rewind-stream _test-error-stream)
11653 #?     # }}}
11654     # check output
11655     (check-stream-equal _test-output-stream  ""  "F - test-index-with-wrong-output-type: output should be empty")
11656     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: output 'o' does not have the right type"  "F - test-index-with-wrong-output-type: error message")
11657     # check that stop(1) was called
11658     (check-ints-equal *(edx+4) 2 "F - test-index-with-wrong-output-type: exit status")
11659     # don't restore from ebp
11660     81 0/subop/add %esp 8/imm32
11661     # . epilogue
11662     5d/pop-to-ebp
11663     c3/return
11665 test-index-with-wrong-output-compound-type:
11666     # . prologue
11667     55/push-ebp
11668     89/<- %ebp 4/r32/esp
11669     # setup
11670     (clear-stream _test-input-stream)
11671     (clear-stream $_test-input-buffered-file->buffer)
11672     (clear-stream _test-output-stream)
11673     (clear-stream $_test-output-buffered-file->buffer)
11674     (clear-stream _test-error-stream)
11675     (clear-stream $_test-error-buffered-file->buffer)
11676     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
11677     68/push 0/imm32
11678     68/push 0/imm32
11679     89/<- %edx 4/r32/esp
11680     (tailor-exit-descriptor %edx 0x10)
11681     #
11682     (write _test-input-stream "fn foo {\n")
11683     (write _test-input-stream "  var a/ebx: (addr array handle boolean) <- copy 0\n")
11684     (write _test-input-stream "  var o/edi: (addr handle int) <- index a, 0\n")
11685     (write _test-input-stream "}\n")
11686     # convert
11687     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
11688     # registers except esp clobbered at this point
11689     # restore ed
11690     89/<- %edx 4/r32/esp
11691     (flush _test-output-buffered-file)
11692     (flush _test-error-buffered-file)
11693 #?     # dump _test-error-stream {{{
11694 #?     (write 2 "^")
11695 #?     (write-stream 2 _test-error-stream)
11696 #?     (write 2 "$\n")
11697 #?     (rewind-stream _test-error-stream)
11698 #?     # }}}
11699     # check output
11700     (check-stream-equal _test-output-stream  ""  "F - test-index-with-wrong-output-compound-type: output should be empty")
11701     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: output 'o' does not have the right type"  "F - test-index-with-wrong-output-compound-type: error message")
11702     # check that stop(1) was called
11703     (check-ints-equal *(edx+4) 2 "F - test-index-with-wrong-output-compound-type: exit status")
11704     # don't restore from ebp
11705     81 0/subop/add %esp 8/imm32
11706     # . epilogue
11707     5d/pop-to-ebp
11708     c3/return
11710 test-index-with-no-inouts:
11711     # . prologue
11712     55/push-ebp
11713     89/<- %ebp 4/r32/esp
11714     # setup
11715     (clear-stream _test-input-stream)
11716     (clear-stream $_test-input-buffered-file->buffer)
11717     (clear-stream _test-output-stream)
11718     (clear-stream $_test-output-buffered-file->buffer)
11719     (clear-stream _test-error-stream)
11720     (clear-stream $_test-error-buffered-file->buffer)
11721     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
11722     68/push 0/imm32
11723     68/push 0/imm32
11724     89/<- %edx 4/r32/esp
11725     (tailor-exit-descriptor %edx 0x10)
11726     #
11727     (write _test-input-stream "fn foo {\n")
11728     (write _test-input-stream "  var c/ecx: (addr int) <- index\n")
11729     (write _test-input-stream "}\n")
11730     # convert
11731     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
11732     # registers except esp clobbered at this point
11733     # restore ed
11734     89/<- %edx 4/r32/esp
11735     (flush _test-output-buffered-file)
11736     (flush _test-error-buffered-file)
11737 #?     # dump _test-error-stream {{{
11738 #?     (write 2 "^")
11739 #?     (write-stream 2 _test-error-stream)
11740 #?     (write 2 "$\n")
11741 #?     (rewind-stream _test-error-stream)
11742 #?     # }}}
11743     # check output
11744     (check-stream-equal _test-output-stream  ""  "F - test-index-with-no-inouts: output should be empty")
11745     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: too few inouts (2 required)"  "F - test-index-with-no-inouts: error message")
11746     # check that stop(1) was called
11747     (check-ints-equal *(edx+4) 2 "F - test-index-with-no-inouts: exit status")
11748     # don't restore from ebp
11749     81 0/subop/add %esp 8/imm32
11750     # . epilogue
11751     5d/pop-to-ebp
11752     c3/return
11754 test-index-with-too-few-inouts:
11755     # . prologue
11756     55/push-ebp
11757     89/<- %ebp 4/r32/esp
11758     # setup
11759     (clear-stream _test-input-stream)
11760     (clear-stream $_test-input-buffered-file->buffer)
11761     (clear-stream _test-output-stream)
11762     (clear-stream $_test-output-buffered-file->buffer)
11763     (clear-stream _test-error-stream)
11764     (clear-stream $_test-error-buffered-file->buffer)
11765     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
11766     68/push 0/imm32
11767     68/push 0/imm32
11768     89/<- %edx 4/r32/esp
11769     (tailor-exit-descriptor %edx 0x10)
11770     #
11771     (write _test-input-stream "fn foo {\n")
11772     (write _test-input-stream "  var a: (array int 3)\n")
11773     (write _test-input-stream "  var c/ecx: (addr int) <- index a\n")
11774     (write _test-input-stream "}\n")
11775     # convert
11776     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
11777     # registers except esp clobbered at this point
11778     # restore ed
11779     89/<- %edx 4/r32/esp
11780     (flush _test-output-buffered-file)
11781     (flush _test-error-buffered-file)
11782 #?     # dump _test-error-stream {{{
11783 #?     (write 2 "^")
11784 #?     (write-stream 2 _test-error-stream)
11785 #?     (write 2 "$\n")
11786 #?     (rewind-stream _test-error-stream)
11787 #?     # }}}
11788     # check output
11789     (check-stream-equal _test-output-stream  ""  "F - test-index-with-too-few-inouts: output should be empty")
11790     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: too few inouts (2 required)"  "F - test-index-with-too-few-inouts: error message")
11791     # check that stop(1) was called
11792     (check-ints-equal *(edx+4) 2 "F - test-index-with-too-few-inouts: exit status")
11793     # don't restore from ebp
11794     81 0/subop/add %esp 8/imm32
11795     # . epilogue
11796     5d/pop-to-ebp
11797     c3/return
11799 test-index-with-too-many-inouts:
11800     # . prologue
11801     55/push-ebp
11802     89/<- %ebp 4/r32/esp
11803     # setup
11804     (clear-stream _test-input-stream)
11805     (clear-stream $_test-input-buffered-file->buffer)
11806     (clear-stream _test-output-stream)
11807     (clear-stream $_test-output-buffered-file->buffer)
11808     (clear-stream _test-error-stream)
11809     (clear-stream $_test-error-buffered-file->buffer)
11810     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
11811     68/push 0/imm32
11812     68/push 0/imm32
11813     89/<- %edx 4/r32/esp
11814     (tailor-exit-descriptor %edx 0x10)
11815     #
11816     (write _test-input-stream "fn foo {\n")
11817     (write _test-input-stream "  var a: (array int 3)\n")
11818     (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0, 0\n")
11819     (write _test-input-stream "}\n")
11820     # convert
11821     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
11822     # registers except esp clobbered at this point
11823     # restore ed
11824     89/<- %edx 4/r32/esp
11825     (flush _test-output-buffered-file)
11826     (flush _test-error-buffered-file)
11827 #?     # dump _test-error-stream {{{
11828 #?     (write 2 "^")
11829 #?     (write-stream 2 _test-error-stream)
11830 #?     (write 2 "$\n")
11831 #?     (rewind-stream _test-error-stream)
11832 #?     # }}}
11833     # check output
11834     (check-stream-equal _test-output-stream  ""  "F - test-index-with-too-many-inouts: output should be empty")
11835     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: too many inouts (2 required)"  "F - test-index-with-too-many-inouts: error message")
11836     # check that stop(1) was called
11837     (check-ints-equal *(edx+4) 2 "F - test-index-with-too-many-inouts: exit status")
11838     # don't restore from ebp
11839     81 0/subop/add %esp 8/imm32
11840     # . epilogue
11841     5d/pop-to-ebp
11842     c3/return
11844 test-index-with-no-output:
11845     # . prologue
11846     55/push-ebp
11847     89/<- %ebp 4/r32/esp
11848     # setup
11849     (clear-stream _test-input-stream)
11850     (clear-stream $_test-input-buffered-file->buffer)
11851     (clear-stream _test-output-stream)
11852     (clear-stream $_test-output-buffered-file->buffer)
11853     (clear-stream _test-error-stream)
11854     (clear-stream $_test-error-buffered-file->buffer)
11855     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
11856     68/push 0/imm32
11857     68/push 0/imm32
11858     89/<- %edx 4/r32/esp
11859     (tailor-exit-descriptor %edx 0x10)
11860     #
11861     (write _test-input-stream "fn foo {\n")
11862     (write _test-input-stream "  var a: (array int 3)\n")
11863     (write _test-input-stream "  index a, 0\n")
11864     (write _test-input-stream "}\n")
11865     # convert
11866     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
11867     # registers except esp clobbered at this point
11868     # restore ed
11869     89/<- %edx 4/r32/esp
11870     (flush _test-output-buffered-file)
11871     (flush _test-error-buffered-file)
11872 #?     # dump _test-error-stream {{{
11873 #?     (write 2 "^")
11874 #?     (write-stream 2 _test-error-stream)
11875 #?     (write 2 "$\n")
11876 #?     (rewind-stream _test-error-stream)
11877 #?     # }}}
11878     # check output
11879     (check-stream-equal _test-output-stream  ""  "F - test-index-with-no-output: output should be empty")
11880     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: must have an output"  "F - test-index-with-no-output: error message")
11881     # check that stop(1) was called
11882     (check-ints-equal *(edx+4) 2 "F - test-index-with-no-output: exit status")
11883     # don't restore from ebp
11884     81 0/subop/add %esp 8/imm32
11885     # . epilogue
11886     5d/pop-to-ebp
11887     c3/return
11889 test-index-with-too-many-outputs:
11890     # . prologue
11891     55/push-ebp
11892     89/<- %ebp 4/r32/esp
11893     # setup
11894     (clear-stream _test-input-stream)
11895     (clear-stream $_test-input-buffered-file->buffer)
11896     (clear-stream _test-output-stream)
11897     (clear-stream $_test-output-buffered-file->buffer)
11898     (clear-stream _test-error-stream)
11899     (clear-stream $_test-error-buffered-file->buffer)
11900     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
11901     68/push 0/imm32
11902     68/push 0/imm32
11903     89/<- %edx 4/r32/esp
11904     (tailor-exit-descriptor %edx 0x10)
11905     #
11906     (write _test-input-stream "fn foo {\n")
11907     (write _test-input-stream "  var a: (array int 3)\n")
11908     (write _test-input-stream "  var b/eax: (addr int) <- copy 0\n")
11909     (write _test-input-stream "  var c/ecx: (addr int) <- copy 0\n")
11910     (write _test-input-stream "  b, c <- index a, 0\n")
11911     (write _test-input-stream "}\n")
11912     # convert
11913     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
11914     # registers except esp clobbered at this point
11915     # restore ed
11916     89/<- %edx 4/r32/esp
11917     (flush _test-output-buffered-file)
11918     (flush _test-error-buffered-file)
11919 #?     # dump _test-error-stream {{{
11920 #?     (write 2 "^")
11921 #?     (write-stream 2 _test-error-stream)
11922 #?     (write 2 "$\n")
11923 #?     (rewind-stream _test-error-stream)
11924 #?     # }}}
11925     # check output
11926     (check-stream-equal _test-output-stream  ""  "F - test-index-with-too-many-outputs: output should be empty")
11927     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: too many outputs (1 required)"  "F - test-index-with-too-many-outputs: error message")
11928     # check that stop(1) was called
11929     (check-ints-equal *(edx+4) 2 "F - test-index-with-too-many-outputs: exit status")
11930     # don't restore from ebp
11931     81 0/subop/add %esp 8/imm32
11932     # . epilogue
11933     5d/pop-to-ebp
11934     c3/return
11936 test-compute-offset-with-non-array-atom-base-type:
11937     # . prologue
11938     55/push-ebp
11939     89/<- %ebp 4/r32/esp
11940     # setup
11941     (clear-stream _test-input-stream)
11942     (clear-stream $_test-input-buffered-file->buffer)
11943     (clear-stream _test-output-stream)
11944     (clear-stream $_test-output-buffered-file->buffer)
11945     (clear-stream _test-error-stream)
11946     (clear-stream $_test-error-buffered-file->buffer)
11947     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
11948     68/push 0/imm32
11949     68/push 0/imm32
11950     89/<- %edx 4/r32/esp
11951     (tailor-exit-descriptor %edx 0x10)
11952     #
11953     (write _test-input-stream "fn foo {\n")
11954     (write _test-input-stream "  var a: int\n")
11955     (write _test-input-stream "  var c/ecx: (offset int) <- compute-offset a, 0\n")
11956     (write _test-input-stream "}\n")
11957     # convert
11958     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
11959     # registers except esp clobbered at this point
11960     # restore ed
11961     89/<- %edx 4/r32/esp
11962     (flush _test-output-buffered-file)
11963     (flush _test-error-buffered-file)
11964 #?     # dump _test-error-stream {{{
11965 #?     (write 2 "^")
11966 #?     (write-stream 2 _test-error-stream)
11967 #?     (write 2 "$\n")
11968 #?     (rewind-stream _test-error-stream)
11969 #?     # }}}
11970     # check output
11971     (check-stream-equal _test-output-stream  ""  "F - test-compute-offset-with-non-array-atom-base-type: output should be empty")
11972     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt compute-offset: var 'a' is not an array"  "F - test-compute-offset-with-non-array-atom-base-type: error message")
11973     # check that stop(1) was called
11974     (check-ints-equal *(edx+4) 2 "F - test-compute-offset-with-non-array-atom-base-type: exit status")
11975     # don't restore from ebp
11976     81 0/subop/add %esp 8/imm32
11977     # . epilogue
11978     5d/pop-to-ebp
11979     c3/return
11981 test-compute-offset-with-non-array-compound-base-type:
11982     # . prologue
11983     55/push-ebp
11984     89/<- %ebp 4/r32/esp
11985     # setup
11986     (clear-stream _test-input-stream)
11987     (clear-stream $_test-input-buffered-file->buffer)
11988     (clear-stream _test-output-stream)
11989     (clear-stream $_test-output-buffered-file->buffer)
11990     (clear-stream _test-error-stream)
11991     (clear-stream $_test-error-buffered-file->buffer)
11992     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
11993     68/push 0/imm32
11994     68/push 0/imm32
11995     89/<- %edx 4/r32/esp
11996     (tailor-exit-descriptor %edx 0x10)
11997     #
11998     (write _test-input-stream "fn foo {\n")
11999     (write _test-input-stream "  var a: (handle int)\n")
12000     (write _test-input-stream "  var c/ecx: (offset int) <- compute-offset a, 0\n")
12001     (write _test-input-stream "}\n")
12002     # convert
12003     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
12004     # registers except esp clobbered at this point
12005     # restore ed
12006     89/<- %edx 4/r32/esp
12007     (flush _test-output-buffered-file)
12008     (flush _test-error-buffered-file)
12009 #?     # dump _test-error-stream {{{
12010 #?     (write 2 "^")
12011 #?     (write-stream 2 _test-error-stream)
12012 #?     (write 2 "$\n")
12013 #?     (rewind-stream _test-error-stream)
12014 #?     # }}}
12015     # check output
12016     (check-stream-equal _test-output-stream  ""  "F - test-compute-offset-with-non-array-compound-base-type: output should be empty")
12017     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt compute-offset: var 'a' is not an array"  "F - test-compute-offset-with-non-array-compound-base-type: error message")
12018     # check that stop(1) was called
12019     (check-ints-equal *(edx+4) 2 "F - test-compute-offset-with-non-array-compound-base-type: exit status")
12020     # don't restore from ebp
12021     81 0/subop/add %esp 8/imm32
12022     # . epilogue
12023     5d/pop-to-ebp
12024     c3/return
12026 test-compute-offset-with-non-array-compound-base-type-2:
12027     # . prologue
12028     55/push-ebp
12029     89/<- %ebp 4/r32/esp
12030     # setup
12031     (clear-stream _test-input-stream)
12032     (clear-stream $_test-input-buffered-file->buffer)
12033     (clear-stream _test-output-stream)
12034     (clear-stream $_test-output-buffered-file->buffer)
12035     (clear-stream _test-error-stream)
12036     (clear-stream $_test-error-buffered-file->buffer)
12037     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
12038     68/push 0/imm32
12039     68/push 0/imm32
12040     89/<- %edx 4/r32/esp
12041     (tailor-exit-descriptor %edx 0x10)
12042     #
12043     (write _test-input-stream "fn foo {\n")
12044     (write _test-input-stream "  var a: (addr int)\n")
12045     (write _test-input-stream "  var c/ecx: (offset int) <- compute-offset a, 0\n")
12046     (write _test-input-stream "}\n")
12047     # convert
12048     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
12049     # registers except esp clobbered at this point
12050     # restore ed
12051     89/<- %edx 4/r32/esp
12052     (flush _test-output-buffered-file)
12053     (flush _test-error-buffered-file)
12054 #?     # dump _test-error-stream {{{
12055 #?     (write 2 "^")
12056 #?     (write-stream 2 _test-error-stream)
12057 #?     (write 2 "$\n")
12058 #?     (rewind-stream _test-error-stream)
12059 #?     # }}}
12060     # check output
12061     (check-stream-equal _test-output-stream  ""  "F - test-compute-offset-with-non-array-compound-base-type-2: output should be empty")
12062     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt compute-offset: var 'a' is not an array"  "F - test-compute-offset-with-non-array-compound-base-type-2: error message")
12063     # check that stop(1) was called
12064     (check-ints-equal *(edx+4) 2 "F - test-compute-offset-with-non-array-compound-base-type-2: exit status")
12065     # don't restore from ebp
12066     81 0/subop/add %esp 8/imm32
12067     # . epilogue
12068     5d/pop-to-ebp
12069     c3/return
12071 test-compute-offset-with-array-atom-base-type:
12072     # . prologue
12073     55/push-ebp
12074     89/<- %ebp 4/r32/esp
12075     # setup
12076     (clear-stream _test-input-stream)
12077     (clear-stream $_test-input-buffered-file->buffer)
12078     (clear-stream _test-output-stream)
12079     (clear-stream $_test-output-buffered-file->buffer)
12080     (clear-stream _test-error-stream)
12081     (clear-stream $_test-error-buffered-file->buffer)
12082     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
12083     68/push 0/imm32
12084     68/push 0/imm32
12085     89/<- %edx 4/r32/esp
12086     (tailor-exit-descriptor %edx 0x10)
12087     #
12088     (write _test-input-stream "fn foo {\n")
12089     (write _test-input-stream "  var a: array\n")
12090     (write _test-input-stream "  var c/ecx: (offset int) <- compute-offset a, 0\n")
12091     (write _test-input-stream "}\n")
12092     # convert
12093     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
12094     # registers except esp clobbered at this point
12095     # restore ed
12096     89/<- %edx 4/r32/esp
12097     (flush _test-output-buffered-file)
12098     (flush _test-error-buffered-file)
12099 #?     # dump _test-error-stream {{{
12100 #?     (write 2 "^")
12101 #?     (write-stream 2 _test-error-stream)
12102 #?     (write 2 "$\n")
12103 #?     (rewind-stream _test-error-stream)
12104 #?     # }}}
12105     # check output
12106     (check-stream-equal _test-output-stream  ""  "F - test-compute-offset-with-array-atom-base-type: output should be empty")
12107     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt compute-offset: array 'a' must specify the type of its elements"  "F - test-compute-offset-with-array-atom-base-type: error message")
12108     # check that stop(1) was called
12109     (check-ints-equal *(edx+4) 2 "F - test-compute-offset-with-array-atom-base-type: exit status")
12110     # don't restore from ebp
12111     81 0/subop/add %esp 8/imm32
12112     # . epilogue
12113     5d/pop-to-ebp
12114     c3/return
12116 test-compute-offset-with-wrong-index-type:
12117     # . prologue
12118     55/push-ebp
12119     89/<- %ebp 4/r32/esp
12120     # setup
12121     (clear-stream _test-input-stream)
12122     (clear-stream $_test-input-buffered-file->buffer)
12123     (clear-stream _test-output-stream)
12124     (clear-stream $_test-output-buffered-file->buffer)
12125     (clear-stream _test-error-stream)
12126     (clear-stream $_test-error-buffered-file->buffer)
12127     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
12128     68/push 0/imm32
12129     68/push 0/imm32
12130     89/<- %edx 4/r32/esp
12131     (tailor-exit-descriptor %edx 0x10)
12132     #
12133     (write _test-input-stream "fn foo {\n")
12134     (write _test-input-stream "  var a/eax: (addr array int) <- copy 0\n")
12135     (write _test-input-stream "  var b: boolean\n")
12136     (write _test-input-stream "  var c/ecx: (offset int) <- compute-offset a, b\n")
12137     (write _test-input-stream "}\n")
12138     # convert
12139     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
12140     # registers except esp clobbered at this point
12141     # restore ed
12142     89/<- %edx 4/r32/esp
12143     (flush _test-output-buffered-file)
12144     (flush _test-error-buffered-file)
12145 #?     # dump _test-error-stream {{{
12146 #?     (write 2 "^")
12147 #?     (write-stream 2 _test-error-stream)
12148 #?     (write 2 "$\n")
12149 #?     (rewind-stream _test-error-stream)
12150 #?     # }}}
12151     # check output
12152     (check-stream-equal _test-output-stream  ""  "F - test-compute-offset-with-wrong-index-type: output should be empty")
12153     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt compute-offset: second argument 'b' must be an int"  "F - test-compute-offset-with-wrong-index-type: error message")
12154     # check that stop(1) was called
12155     (check-ints-equal *(edx+4) 2 "F - test-compute-offset-with-wrong-index-type: exit status")
12156     # don't restore from ebp
12157     81 0/subop/add %esp 8/imm32
12158     # . epilogue
12159     5d/pop-to-ebp
12160     c3/return
12162 test-compute-offset-with-output-not-offset:
12163     # . prologue
12164     55/push-ebp
12165     89/<- %ebp 4/r32/esp
12166     # setup
12167     (clear-stream _test-input-stream)
12168     (clear-stream $_test-input-buffered-file->buffer)
12169     (clear-stream _test-output-stream)
12170     (clear-stream $_test-output-buffered-file->buffer)
12171     (clear-stream _test-error-stream)
12172     (clear-stream $_test-error-buffered-file->buffer)
12173     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
12174     68/push 0/imm32
12175     68/push 0/imm32
12176     89/<- %edx 4/r32/esp
12177     (tailor-exit-descriptor %edx 0x10)
12178     #
12179     (write _test-input-stream "fn foo {\n")
12180     (write _test-input-stream "  var a/ebx: (addr array boolean) <- copy 0\n")
12181     (write _test-input-stream "  var o/edi: int <- compute-offset a, 0\n")
12182     (write _test-input-stream "}\n")
12183     # convert
12184     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
12185     # registers except esp clobbered at this point
12186     # restore ed
12187     89/<- %edx 4/r32/esp
12188     (flush _test-output-buffered-file)
12189     (flush _test-error-buffered-file)
12190 #?     # dump _test-error-stream {{{
12191 #?     (write 2 "^")
12192 #?     (write-stream 2 _test-error-stream)
12193 #?     (write 2 "$\n")
12194 #?     (rewind-stream _test-error-stream)
12195 #?     # }}}
12196     # check output
12197     (check-stream-equal _test-output-stream  ""  "F - test-compute-offset-with-output-not-offset: output should be empty")
12198     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt compute-offset: output 'o' must be an offset"  "F - test-compute-offset-with-output-not-offset: error message")
12199     # check that stop(1) was called
12200     (check-ints-equal *(edx+4) 2 "F - test-compute-offset-with-output-not-offset: exit status")
12201     # don't restore from ebp
12202     81 0/subop/add %esp 8/imm32
12203     # . epilogue
12204     5d/pop-to-ebp
12205     c3/return
12207 test-compute-offset-with-output-not-address-2:
12208     # . prologue
12209     55/push-ebp
12210     89/<- %ebp 4/r32/esp
12211     # setup
12212     (clear-stream _test-input-stream)
12213     (clear-stream $_test-input-buffered-file->buffer)
12214     (clear-stream _test-output-stream)
12215     (clear-stream $_test-output-buffered-file->buffer)
12216     (clear-stream _test-error-stream)
12217     (clear-stream $_test-error-buffered-file->buffer)
12218     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
12219     68/push 0/imm32
12220     68/push 0/imm32
12221     89/<- %edx 4/r32/esp
12222     (tailor-exit-descriptor %edx 0x10)
12223     #
12224     (write _test-input-stream "fn foo {\n")
12225     (write _test-input-stream "  var a/ebx: (addr array boolean) <- copy 0\n")
12226     (write _test-input-stream "  var o/edi: (int) <- compute-offset a, 0\n")
12227     (write _test-input-stream "}\n")
12228     # convert
12229     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
12230     # registers except esp clobbered at this point
12231     # restore ed
12232     89/<- %edx 4/r32/esp
12233     (flush _test-output-buffered-file)
12234     (flush _test-error-buffered-file)
12235 #?     # dump _test-error-stream {{{
12236 #?     (write 2 "^")
12237 #?     (write-stream 2 _test-error-stream)
12238 #?     (write 2 "$\n")
12239 #?     (rewind-stream _test-error-stream)
12240 #?     # }}}
12241     # check output
12242     (check-stream-equal _test-output-stream  ""  "F - test-compute-offset-with-output-not-address-2: output should be empty")
12243     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt compute-offset: output 'o' must be an offset"  "F - test-compute-offset-with-output-not-address-2: error message")
12244     # check that stop(1) was called
12245     (check-ints-equal *(edx+4) 2 "F - test-compute-offset-with-output-not-address-2: exit status")
12246     # don't restore from ebp
12247     81 0/subop/add %esp 8/imm32
12248     # . epilogue
12249     5d/pop-to-ebp
12250     c3/return
12252 test-compute-offset-with-wrong-output-type:
12253     # . prologue
12254     55/push-ebp
12255     89/<- %ebp 4/r32/esp
12256     # setup
12257     (clear-stream _test-input-stream)
12258     (clear-stream $_test-input-buffered-file->buffer)
12259     (clear-stream _test-output-stream)
12260     (clear-stream $_test-output-buffered-file->buffer)
12261     (clear-stream _test-error-stream)
12262     (clear-stream $_test-error-buffered-file->buffer)
12263     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
12264     68/push 0/imm32
12265     68/push 0/imm32
12266     89/<- %edx 4/r32/esp
12267     (tailor-exit-descriptor %edx 0x10)
12268     #
12269     (write _test-input-stream "fn foo {\n")
12270     (write _test-input-stream "  var a/ebx: (addr array boolean) <- copy 0\n")
12271     (write _test-input-stream "  var o/edi: (offset int) <- compute-offset a, 0\n")
12272     (write _test-input-stream "}\n")
12273     # convert
12274     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
12275     # registers except esp clobbered at this point
12276     # restore ed
12277     89/<- %edx 4/r32/esp
12278     (flush _test-output-buffered-file)
12279     (flush _test-error-buffered-file)
12280 #?     # dump _test-error-stream {{{
12281 #?     (write 2 "^")
12282 #?     (write-stream 2 _test-error-stream)
12283 #?     (write 2 "$\n")
12284 #?     (rewind-stream _test-error-stream)
12285 #?     # }}}
12286     # check output
12287     (check-stream-equal _test-output-stream  ""  "F - test-compute-offset-with-wrong-output-type: output should be empty")
12288     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt compute-offset: output 'o' does not have the right type"  "F - test-compute-offset-with-wrong-output-type: error message")
12289     # check that stop(1) was called
12290     (check-ints-equal *(edx+4) 2 "F - test-compute-offset-with-wrong-output-type: exit status")
12291     # don't restore from ebp
12292     81 0/subop/add %esp 8/imm32
12293     # . epilogue
12294     5d/pop-to-ebp
12295     c3/return
12297 test-compute-offset-with-wrong-output-compound-type:
12298     # . prologue
12299     55/push-ebp
12300     89/<- %ebp 4/r32/esp
12301     # setup
12302     (clear-stream _test-input-stream)
12303     (clear-stream $_test-input-buffered-file->buffer)
12304     (clear-stream _test-output-stream)
12305     (clear-stream $_test-output-buffered-file->buffer)
12306     (clear-stream _test-error-stream)
12307     (clear-stream $_test-error-buffered-file->buffer)
12308     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
12309     68/push 0/imm32
12310     68/push 0/imm32
12311     89/<- %edx 4/r32/esp
12312     (tailor-exit-descriptor %edx 0x10)
12313     #
12314     (write _test-input-stream "fn foo {\n")
12315     (write _test-input-stream "  var a/ebx: (addr array handle boolean) <- copy 0\n")
12316     (write _test-input-stream "  var o/edi: (offset handle int) <- compute-offset a, 0\n")
12317     (write _test-input-stream "}\n")
12318     # convert
12319     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
12320     # registers except esp clobbered at this point
12321     # restore ed
12322     89/<- %edx 4/r32/esp
12323     (flush _test-output-buffered-file)
12324     (flush _test-error-buffered-file)
12325 #?     # dump _test-error-stream {{{
12326 #?     (write 2 "^")
12327 #?     (write-stream 2 _test-error-stream)
12328 #?     (write 2 "$\n")
12329 #?     (rewind-stream _test-error-stream)
12330 #?     # }}}
12331     # check output
12332     (check-stream-equal _test-output-stream  ""  "F - test-compute-offset-with-wrong-output-compound-type: output should be empty")
12333     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt compute-offset: output 'o' does not have the right type"  "F - test-compute-offset-with-wrong-output-compound-type: error message")
12334     # check that stop(1) was called
12335     (check-ints-equal *(edx+4) 2 "F - test-compute-offset-with-wrong-output-compound-type: exit status")
12336     # don't restore from ebp
12337     81 0/subop/add %esp 8/imm32
12338     # . epilogue
12339     5d/pop-to-ebp
12340     c3/return
12342 test-compute-offset-with-no-inouts:
12343     # . prologue
12344     55/push-ebp
12345     89/<- %ebp 4/r32/esp
12346     # setup
12347     (clear-stream _test-input-stream)
12348     (clear-stream $_test-input-buffered-file->buffer)
12349     (clear-stream _test-output-stream)
12350     (clear-stream $_test-output-buffered-file->buffer)
12351     (clear-stream _test-error-stream)
12352     (clear-stream $_test-error-buffered-file->buffer)
12353     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
12354     68/push 0/imm32
12355     68/push 0/imm32
12356     89/<- %edx 4/r32/esp
12357     (tailor-exit-descriptor %edx 0x10)
12358     #
12359     (write _test-input-stream "fn foo {\n")
12360     (write _test-input-stream "  var c/ecx: (offset int) <- compute-offset\n")
12361     (write _test-input-stream "}\n")
12362     # convert
12363     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
12364     # registers except esp clobbered at this point
12365     # restore ed
12366     89/<- %edx 4/r32/esp
12367     (flush _test-output-buffered-file)
12368     (flush _test-error-buffered-file)
12369 #?     # dump _test-error-stream {{{
12370 #?     (write 2 "^")
12371 #?     (write-stream 2 _test-error-stream)
12372 #?     (write 2 "$\n")
12373 #?     (rewind-stream _test-error-stream)
12374 #?     # }}}
12375     # check output
12376     (check-stream-equal _test-output-stream  ""  "F - test-compute-offset-with-no-inouts: output should be empty")
12377     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt compute-offset: too few inouts (2 required)"  "F - test-compute-offset-with-no-inouts: error message")
12378     # check that stop(1) was called
12379     (check-ints-equal *(edx+4) 2 "F - test-compute-offset-with-no-inouts: exit status")
12380     # don't restore from ebp
12381     81 0/subop/add %esp 8/imm32
12382     # . epilogue
12383     5d/pop-to-ebp
12384     c3/return
12386 test-compute-offset-with-too-few-inouts:
12387     # . prologue
12388     55/push-ebp
12389     89/<- %ebp 4/r32/esp
12390     # setup
12391     (clear-stream _test-input-stream)
12392     (clear-stream $_test-input-buffered-file->buffer)
12393     (clear-stream _test-output-stream)
12394     (clear-stream $_test-output-buffered-file->buffer)
12395     (clear-stream _test-error-stream)
12396     (clear-stream $_test-error-buffered-file->buffer)
12397     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
12398     68/push 0/imm32
12399     68/push 0/imm32
12400     89/<- %edx 4/r32/esp
12401     (tailor-exit-descriptor %edx 0x10)
12402     #
12403     (write _test-input-stream "fn foo {\n")
12404     (write _test-input-stream "  var a: (array int 3)\n")
12405     (write _test-input-stream "  var c/ecx: (offset int) <- compute-offset a\n")
12406     (write _test-input-stream "}\n")
12407     # convert
12408     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
12409     # registers except esp clobbered at this point
12410     # restore ed
12411     89/<- %edx 4/r32/esp
12412     (flush _test-output-buffered-file)
12413     (flush _test-error-buffered-file)
12414 #?     # dump _test-error-stream {{{
12415 #?     (write 2 "^")
12416 #?     (write-stream 2 _test-error-stream)
12417 #?     (write 2 "$\n")
12418 #?     (rewind-stream _test-error-stream)
12419 #?     # }}}
12420     # check output
12421     (check-stream-equal _test-output-stream  ""  "F - test-compute-offset-with-too-few-inouts: output should be empty")
12422     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt compute-offset: too few inouts (2 required)"  "F - test-compute-offset-with-too-few-inouts: error message")
12423     # check that stop(1) was called
12424     (check-ints-equal *(edx+4) 2 "F - test-compute-offset-with-too-few-inouts: exit status")
12425     # don't restore from ebp
12426     81 0/subop/add %esp 8/imm32
12427     # . epilogue
12428     5d/pop-to-ebp
12429     c3/return
12431 test-compute-offset-with-too-many-inouts:
12432     # . prologue
12433     55/push-ebp
12434     89/<- %ebp 4/r32/esp
12435     # setup
12436     (clear-stream _test-input-stream)
12437     (clear-stream $_test-input-buffered-file->buffer)
12438     (clear-stream _test-output-stream)
12439     (clear-stream $_test-output-buffered-file->buffer)
12440     (clear-stream _test-error-stream)
12441     (clear-stream $_test-error-buffered-file->buffer)
12442     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
12443     68/push 0/imm32
12444     68/push 0/imm32
12445     89/<- %edx 4/r32/esp
12446     (tailor-exit-descriptor %edx 0x10)
12447     #
12448     (write _test-input-stream "fn foo {\n")
12449     (write _test-input-stream "  var a: (array int 3)\n")
12450     (write _test-input-stream "  var c/ecx: (offset int) <- compute-offset a, 0, 0\n")
12451     (write _test-input-stream "}\n")
12452     # convert
12453     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
12454     # registers except esp clobbered at this point
12455     # restore ed
12456     89/<- %edx 4/r32/esp
12457     (flush _test-output-buffered-file)
12458     (flush _test-error-buffered-file)
12459 #?     # dump _test-error-stream {{{
12460 #?     (write 2 "^")
12461 #?     (write-stream 2 _test-error-stream)
12462 #?     (write 2 "$\n")
12463 #?     (rewind-stream _test-error-stream)
12464 #?     # }}}
12465     # check output
12466     (check-stream-equal _test-output-stream  ""  "F - test-compute-offset-with-too-many-inouts: output should be empty")
12467     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt compute-offset: too many inouts (2 required)"  "F - test-compute-offset-with-too-many-inouts: error message")
12468     # check that stop(1) was called
12469     (check-ints-equal *(edx+4) 2 "F - test-compute-offset-with-too-many-inouts: exit status")
12470     # don't restore from ebp
12471     81 0/subop/add %esp 8/imm32
12472     # . epilogue
12473     5d/pop-to-ebp
12474     c3/return
12476 test-compute-offset-with-no-output:
12477     # . prologue
12478     55/push-ebp
12479     89/<- %ebp 4/r32/esp
12480     # setup
12481     (clear-stream _test-input-stream)
12482     (clear-stream $_test-input-buffered-file->buffer)
12483     (clear-stream _test-output-stream)
12484     (clear-stream $_test-output-buffered-file->buffer)
12485     (clear-stream _test-error-stream)
12486     (clear-stream $_test-error-buffered-file->buffer)
12487     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
12488     68/push 0/imm32
12489     68/push 0/imm32
12490     89/<- %edx 4/r32/esp
12491     (tailor-exit-descriptor %edx 0x10)
12492     #
12493     (write _test-input-stream "fn foo {\n")
12494     (write _test-input-stream "  var a: (array int 3)\n")
12495     (write _test-input-stream "  compute-offset a, 0\n")
12496     (write _test-input-stream "}\n")
12497     # convert
12498     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
12499     # registers except esp clobbered at this point
12500     # restore ed
12501     89/<- %edx 4/r32/esp
12502     (flush _test-output-buffered-file)
12503     (flush _test-error-buffered-file)
12504 #?     # dump _test-error-stream {{{
12505 #?     (write 2 "^")
12506 #?     (write-stream 2 _test-error-stream)
12507 #?     (write 2 "$\n")
12508 #?     (rewind-stream _test-error-stream)
12509 #?     # }}}
12510     # check output
12511     (check-stream-equal _test-output-stream  ""  "F - test-compute-offset-with-no-output: output should be empty")
12512     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt compute-offset: must have an output"  "F - test-compute-offset-with-no-output: error message")
12513     # check that stop(1) was called
12514     (check-ints-equal *(edx+4) 2 "F - test-compute-offset-with-no-output: exit status")
12515     # don't restore from ebp
12516     81 0/subop/add %esp 8/imm32
12517     # . epilogue
12518     5d/pop-to-ebp
12519     c3/return
12521 test-compute-offset-with-too-many-outputs:
12522     # . prologue
12523     55/push-ebp
12524     89/<- %ebp 4/r32/esp
12525     # setup
12526     (clear-stream _test-input-stream)
12527     (clear-stream $_test-input-buffered-file->buffer)
12528     (clear-stream _test-output-stream)
12529     (clear-stream $_test-output-buffered-file->buffer)
12530     (clear-stream _test-error-stream)
12531     (clear-stream $_test-error-buffered-file->buffer)
12532     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
12533     68/push 0/imm32
12534     68/push 0/imm32
12535     89/<- %edx 4/r32/esp
12536     (tailor-exit-descriptor %edx 0x10)
12537     #
12538     (write _test-input-stream "fn foo {\n")
12539     (write _test-input-stream "  var a: (array int 3)\n")
12540     (write _test-input-stream "  var b/eax: (offset int) <- compute-offset a, 0\n")
12541     (write _test-input-stream "  var c/ecx: (addr int) <- copy 0\n")
12542     (write _test-input-stream "  b, c <- compute-offset a, 0\n")
12543     (write _test-input-stream "}\n")
12544     # convert
12545     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
12546     # registers except esp clobbered at this point
12547     # restore ed
12548     89/<- %edx 4/r32/esp
12549     (flush _test-output-buffered-file)
12550     (flush _test-error-buffered-file)
12551 #?     # dump _test-error-stream {{{
12552 #?     (write 2 "^")
12553 #?     (write-stream 2 _test-error-stream)
12554 #?     (write 2 "$\n")
12555 #?     (rewind-stream _test-error-stream)
12556 #?     # }}}
12557     # check output
12558     (check-stream-equal _test-output-stream  ""  "F - test-compute-offset-with-too-many-outputs: output should be empty")
12559     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt compute-offset: too many outputs (1 required)"  "F - test-compute-offset-with-too-many-outputs: error message")
12560     # check that stop(1) was called
12561     (check-ints-equal *(edx+4) 2 "F - test-compute-offset-with-too-many-outputs: exit status")
12562     # don't restore from ebp
12563     81 0/subop/add %esp 8/imm32
12564     # . epilogue
12565     5d/pop-to-ebp
12566     c3/return
12568 test-convert-read-from-stream:
12569     # . prologue
12570     55/push-ebp
12571     89/<- %ebp 4/r32/esp
12572     # setup
12573     (clear-stream _test-input-stream)
12574     (clear-stream $_test-input-buffered-file->buffer)
12575     (clear-stream _test-output-stream)
12576     (clear-stream $_test-output-buffered-file->buffer)
12577     #
12578     (write _test-input-stream "fn foo {\n")
12579     (write _test-input-stream "  var s/esi: (addr stream int) <- copy 0\n")
12580     (write _test-input-stream "  var o/ecx: (addr int) <- copy 0\n")
12581     (write _test-input-stream "  read-from-stream s, o\n")
12582     (write _test-input-stream "}\n")
12583     # convert
12584     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
12585     # registers except esp clobbered at this point
12586     # restore ed
12587     89/<- %edx 4/r32/esp
12588     (flush _test-output-buffered-file)
12589     (flush _test-error-buffered-file)
12590 #?     # dump _test-output-stream {{{
12591 #?     (write 2 "^")
12592 #?     (write-stream 2 _test-output-stream)
12593 #?     (write 2 "$\n")
12594 #?     (rewind-stream _test-output-stream)
12595 #?     # }}}
12596     # check output
12597     (check-next-stream-line-equal _test-output-stream "foo:"                            "F - test-convert-read-from-stream/0")
12598     (check-next-stream-line-equal _test-output-stream "  # . prologue"                  "F - test-convert-read-from-stream/1")
12599     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                   "F - test-convert-read-from-stream/2")
12600     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"          "F - test-convert-read-from-stream/3")
12601     (check-next-stream-line-equal _test-output-stream "  {"                             "F - test-convert-read-from-stream/4")
12602     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"           "F - test-convert-read-from-stream/5")
12603     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %esi"        "F - test-convert-read-from-stream/6")
12604     (check-next-stream-line-equal _test-output-stream "    be/copy-to-esi 0/imm32"      "F - test-convert-read-from-stream/7")
12605     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"        "F - test-convert-read-from-stream/8")
12606     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"      "F - test-convert-read-from-stream/9")
12607     (check-next-stream-line-equal _test-output-stream "    (read-from-stream %esi %ecx 0x00000004)"  "F - test-convert-read-from-stream/10")
12608     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"         "F - test-convert-read-from-stream/11")
12609     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %esi"         "F - test-convert-read-from-stream/12")
12610     (check-next-stream-line-equal _test-output-stream "  }"                             "F - test-convert-read-from-stream/13")
12611     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"          "F - test-convert-read-from-stream/14")
12612     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                  "F - test-convert-read-from-stream/15")
12613     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"          "F - test-convert-read-from-stream/16")
12614     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                 "F - test-convert-read-from-stream/17")
12615     (check-next-stream-line-equal _test-output-stream "  c3/return"                     "F - test-convert-read-from-stream/18")
12616     # . epilogue
12617     89/<- %esp 5/r32/ebp
12618     5d/pop-to-ebp
12619     c3/return
12621 test-convert-read-from-stream-with-correct-payload-size:
12622     # . prologue
12623     55/push-ebp
12624     89/<- %ebp 4/r32/esp
12625     # setup
12626     (clear-stream _test-input-stream)
12627     (clear-stream $_test-input-buffered-file->buffer)
12628     (clear-stream _test-output-stream)
12629     (clear-stream $_test-output-buffered-file->buffer)
12630     #
12631     (write _test-input-stream "fn foo {\n")
12632     (write _test-input-stream "  var s/esi: (addr stream handle int) <- copy 0\n")
12633     (write _test-input-stream "  var o/ecx: (addr handle int) <- copy 0\n")
12634     (write _test-input-stream "  read-from-stream s, o\n")
12635     (write _test-input-stream "}\n")
12636     # convert
12637     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
12638     # registers except esp clobbered at this point
12639     # restore ed
12640     89/<- %edx 4/r32/esp
12641     (flush _test-output-buffered-file)
12642     (flush _test-error-buffered-file)
12643 #?     # dump _test-output-stream {{{
12644 #?     (write 2 "^")
12645 #?     (write-stream 2 _test-output-stream)
12646 #?     (write 2 "$\n")
12647 #?     (rewind-stream _test-output-stream)
12648 #?     # }}}
12649     # check output
12650     (check-next-stream-line-equal _test-output-stream "foo:"                            "F - test-convert-read-from-stream-with-correct-payload-size/0")
12651     (check-next-stream-line-equal _test-output-stream "  # . prologue"                  "F - test-convert-read-from-stream-with-correct-payload-size/1")
12652     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                   "F - test-convert-read-from-stream-with-correct-payload-size/2")
12653     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"          "F - test-convert-read-from-stream-with-correct-payload-size/3")
12654     (check-next-stream-line-equal _test-output-stream "  {"                             "F - test-convert-read-from-stream-with-correct-payload-size/4")
12655     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"           "F - test-convert-read-from-stream-with-correct-payload-size/5")
12656     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %esi"        "F - test-convert-read-from-stream-with-correct-payload-size/6")
12657     (check-next-stream-line-equal _test-output-stream "    be/copy-to-esi 0/imm32"      "F - test-convert-read-from-stream-with-correct-payload-size/7")
12658     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"        "F - test-convert-read-from-stream-with-correct-payload-size/8")
12659     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"      "F - test-convert-read-from-stream-with-correct-payload-size/9")
12660     (check-next-stream-line-equal _test-output-stream "    (read-from-stream %esi %ecx 0x00000008)"  "F - test-convert-read-from-stream-with-correct-payload-size/10")
12661     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"         "F - test-convert-read-from-stream-with-correct-payload-size/11")
12662     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %esi"         "F - test-convert-read-from-stream-with-correct-payload-size/12")
12663     (check-next-stream-line-equal _test-output-stream "  }"                             "F - test-convert-read-from-stream-with-correct-payload-size/13")
12664     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"          "F - test-convert-read-from-stream-with-correct-payload-size/14")
12665     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                  "F - test-convert-read-from-stream-with-correct-payload-size/15")
12666     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"          "F - test-convert-read-from-stream-with-correct-payload-size/16")
12667     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                 "F - test-convert-read-from-stream-with-correct-payload-size/17")
12668     (check-next-stream-line-equal _test-output-stream "  c3/return"                     "F - test-convert-read-from-stream-with-correct-payload-size/18")
12669     # . epilogue
12670     89/<- %esp 5/r32/ebp
12671     5d/pop-to-ebp
12672     c3/return
12674 test-read-from-stream-with-non-stream-atom-base-type:
12675     # . prologue
12676     55/push-ebp
12677     89/<- %ebp 4/r32/esp
12678     # setup
12679     (clear-stream _test-input-stream)
12680     (clear-stream $_test-input-buffered-file->buffer)
12681     (clear-stream _test-output-stream)
12682     (clear-stream $_test-output-buffered-file->buffer)
12683     (clear-stream _test-error-stream)
12684     (clear-stream $_test-error-buffered-file->buffer)
12685     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
12686     68/push 0/imm32
12687     68/push 0/imm32
12688     89/<- %edx 4/r32/esp
12689     (tailor-exit-descriptor %edx 0x10)
12690     #
12691     (write _test-input-stream "fn foo {\n")
12692     (write _test-input-stream "  var a: int\n")
12693     (write _test-input-stream "  read-from-stream a, 0\n")
12694     (write _test-input-stream "}\n")
12695     # convert
12696     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
12697     # registers except esp clobbered at this point
12698     # restore ed
12699     89/<- %edx 4/r32/esp
12700     (flush _test-output-buffered-file)
12701     (flush _test-error-buffered-file)
12702 #?     # dump _test-error-stream {{{
12703 #?     (write 2 "^")
12704 #?     (write-stream 2 _test-error-stream)
12705 #?     (write 2 "$\n")
12706 #?     (rewind-stream _test-error-stream)
12707 #?     # }}}
12708     # check output
12709     (check-stream-equal _test-output-stream  ""  "F - test-read-from-stream-with-non-stream-atom-base-type: output should be empty")
12710     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt read-from-stream: var 'a' must be an addr to a stream"  "F - test-read-from-stream-with-non-stream-atom-base-type: error message")
12711     # check that stop(1) was called
12712     (check-ints-equal *(edx+4) 2 "F - test-read-from-stream-with-non-stream-atom-base-type: exit status")
12713     # don't restore from ebp
12714     81 0/subop/add %esp 8/imm32
12715     # . epilogue
12716     5d/pop-to-ebp
12717     c3/return
12719 test-read-from-stream-with-non-stream-compound-base-type:
12720     # . prologue
12721     55/push-ebp
12722     89/<- %ebp 4/r32/esp
12723     # setup
12724     (clear-stream _test-input-stream)
12725     (clear-stream $_test-input-buffered-file->buffer)
12726     (clear-stream _test-output-stream)
12727     (clear-stream $_test-output-buffered-file->buffer)
12728     (clear-stream _test-error-stream)
12729     (clear-stream $_test-error-buffered-file->buffer)
12730     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
12731     68/push 0/imm32
12732     68/push 0/imm32
12733     89/<- %edx 4/r32/esp
12734     (tailor-exit-descriptor %edx 0x10)
12735     #
12736     (write _test-input-stream "fn foo {\n")
12737     (write _test-input-stream "  var a: (handle int)\n")
12738     (write _test-input-stream "  read-from-stream a, 0\n")
12739     (write _test-input-stream "}\n")
12740     # convert
12741     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
12742     # registers except esp clobbered at this point
12743     # restore ed
12744     89/<- %edx 4/r32/esp
12745     (flush _test-output-buffered-file)
12746     (flush _test-error-buffered-file)
12747 #?     # dump _test-error-stream {{{
12748 #?     (write 2 "^")
12749 #?     (write-stream 2 _test-error-stream)
12750 #?     (write 2 "$\n")
12751 #?     (rewind-stream _test-error-stream)
12752 #?     # }}}
12753     # check output
12754     (check-stream-equal _test-output-stream  ""  "F - test-read-from-stream-with-non-stream-compound-base-type: output should be empty")
12755     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt read-from-stream: var 'a' must be an addr to a stream"  "F - test-read-from-stream-with-non-stream-compound-base-type: error message")
12756     # check that stop(1) was called
12757     (check-ints-equal *(edx+4) 2 "F - test-read-from-stream-with-non-stream-compound-base-type: exit status")
12758     # don't restore from ebp
12759     81 0/subop/add %esp 8/imm32
12760     # . epilogue
12761     5d/pop-to-ebp
12762     c3/return
12764 test-read-from-stream-with-non-stream-compound-base-type-2:
12765     # . prologue
12766     55/push-ebp
12767     89/<- %ebp 4/r32/esp
12768     # setup
12769     (clear-stream _test-input-stream)
12770     (clear-stream $_test-input-buffered-file->buffer)
12771     (clear-stream _test-output-stream)
12772     (clear-stream $_test-output-buffered-file->buffer)
12773     (clear-stream _test-error-stream)
12774     (clear-stream $_test-error-buffered-file->buffer)
12775     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
12776     68/push 0/imm32
12777     68/push 0/imm32
12778     89/<- %edx 4/r32/esp
12779     (tailor-exit-descriptor %edx 0x10)
12780     #
12781     (write _test-input-stream "fn foo {\n")
12782     (write _test-input-stream "  var a: (addr int)\n")
12783     (write _test-input-stream "  read-from-stream a, 0\n")
12784     (write _test-input-stream "}\n")
12785     # convert
12786     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
12787     # registers except esp clobbered at this point
12788     # restore ed
12789     89/<- %edx 4/r32/esp
12790     (flush _test-output-buffered-file)
12791     (flush _test-error-buffered-file)
12792 #?     # dump _test-error-stream {{{
12793 #?     (write 2 "^")
12794 #?     (write-stream 2 _test-error-stream)
12795 #?     (write 2 "$\n")
12796 #?     (rewind-stream _test-error-stream)
12797 #?     # }}}
12798     # check output
12799     (check-stream-equal _test-output-stream  ""  "F - test-read-from-stream-with-non-stream-compound-base-type-2: output should be empty")
12800     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt read-from-stream: var 'a' must be an addr to a stream"  "F - test-read-from-stream-with-non-stream-compound-base-type-2: error message")
12801     # check that stop(1) was called
12802     (check-ints-equal *(edx+4) 2 "F - test-read-from-stream-with-non-stream-compound-base-type-2: exit status")
12803     # don't restore from ebp
12804     81 0/subop/add %esp 8/imm32
12805     # . epilogue
12806     5d/pop-to-ebp
12807     c3/return
12809 test-read-from-stream-with-stream-atom-base-type:
12810     # . prologue
12811     55/push-ebp
12812     89/<- %ebp 4/r32/esp
12813     # setup
12814     (clear-stream _test-input-stream)
12815     (clear-stream $_test-input-buffered-file->buffer)
12816     (clear-stream _test-output-stream)
12817     (clear-stream $_test-output-buffered-file->buffer)
12818     (clear-stream _test-error-stream)
12819     (clear-stream $_test-error-buffered-file->buffer)
12820     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
12821     68/push 0/imm32
12822     68/push 0/imm32
12823     89/<- %edx 4/r32/esp
12824     (tailor-exit-descriptor %edx 0x10)
12825     #
12826     (write _test-input-stream "fn foo {\n")
12827     (write _test-input-stream "  var a: stream\n")
12828     (write _test-input-stream "  read-from-stream a, 0\n")
12829     (write _test-input-stream "}\n")
12830     # convert
12831     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
12832     # registers except esp clobbered at this point
12833     # restore ed
12834     89/<- %edx 4/r32/esp
12835     (flush _test-output-buffered-file)
12836     (flush _test-error-buffered-file)
12837 #?     # dump _test-error-stream {{{
12838 #?     (write 2 "^")
12839 #?     (write-stream 2 _test-error-stream)
12840 #?     (write 2 "$\n")
12841 #?     (rewind-stream _test-error-stream)
12842 #?     # }}}
12843     # check output
12844     (check-stream-equal _test-output-stream  ""  "F - test-read-from-stream-with-stream-atom-base-type: output should be empty")
12845     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt read-from-stream: var 'a' must be an addr to a stream"  "F - test-read-from-stream-with-stream-atom-base-type: error message")
12846     # check that stop(1) was called
12847     (check-ints-equal *(edx+4) 2 "F - test-read-from-stream-with-stream-atom-base-type: exit status")
12848     # don't restore from ebp
12849     81 0/subop/add %esp 8/imm32
12850     # . epilogue
12851     5d/pop-to-ebp
12852     c3/return
12854 test-read-from-stream-with-wrong-index-type:
12855     # . prologue
12856     55/push-ebp
12857     89/<- %ebp 4/r32/esp
12858     # setup
12859     (clear-stream _test-input-stream)
12860     (clear-stream $_test-input-buffered-file->buffer)
12861     (clear-stream _test-output-stream)
12862     (clear-stream $_test-output-buffered-file->buffer)
12863     (clear-stream _test-error-stream)
12864     (clear-stream $_test-error-buffered-file->buffer)
12865     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
12866     68/push 0/imm32
12867     68/push 0/imm32
12868     89/<- %edx 4/r32/esp
12869     (tailor-exit-descriptor %edx 0x10)
12870     #
12871     (write _test-input-stream "fn foo {\n")
12872     (write _test-input-stream "  var a/eax: (addr stream int) <- copy 0\n")
12873     (write _test-input-stream "  var b: boolean\n")
12874     (write _test-input-stream "  read-from-stream a, b\n")
12875     (write _test-input-stream "}\n")
12876     # convert
12877     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
12878     # registers except esp clobbered at this point
12879     # restore ed
12880     89/<- %edx 4/r32/esp
12881     (flush _test-output-buffered-file)
12882     (flush _test-error-buffered-file)
12883 #?     # dump _test-error-stream {{{
12884 #?     (write 2 "^")
12885 #?     (write-stream 2 _test-error-stream)
12886 #?     (write 2 "$\n")
12887 #?     (rewind-stream _test-error-stream)
12888 #?     # }}}
12889     # check output
12890     (check-stream-equal _test-output-stream  ""  "F - test-read-from-stream-with-wrong-index-type: output should be empty")
12891     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt read-from-stream: target 'b' must be an addr"  "F - test-read-from-stream-with-wrong-index-type: error message")
12892     # check that stop(1) was called
12893     (check-ints-equal *(edx+4) 2 "F - test-read-from-stream-with-wrong-index-type: exit status")
12894     # don't restore from ebp
12895     81 0/subop/add %esp 8/imm32
12896     # . epilogue
12897     5d/pop-to-ebp
12898     c3/return
12900 test-read-from-stream-with-no-inouts:
12901     # . prologue
12902     55/push-ebp
12903     89/<- %ebp 4/r32/esp
12904     # setup
12905     (clear-stream _test-input-stream)
12906     (clear-stream $_test-input-buffered-file->buffer)
12907     (clear-stream _test-output-stream)
12908     (clear-stream $_test-output-buffered-file->buffer)
12909     (clear-stream _test-error-stream)
12910     (clear-stream $_test-error-buffered-file->buffer)
12911     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
12912     68/push 0/imm32
12913     68/push 0/imm32
12914     89/<- %edx 4/r32/esp
12915     (tailor-exit-descriptor %edx 0x10)
12916     #
12917     (write _test-input-stream "fn foo {\n")
12918     (write _test-input-stream "  read-from-stream\n")
12919     (write _test-input-stream "}\n")
12920     # convert
12921     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
12922     # registers except esp clobbered at this point
12923     # restore ed
12924     89/<- %edx 4/r32/esp
12925     (flush _test-output-buffered-file)
12926     (flush _test-error-buffered-file)
12927 #?     # dump _test-error-stream {{{
12928 #?     (write 2 "^")
12929 #?     (write-stream 2 _test-error-stream)
12930 #?     (write 2 "$\n")
12931 #?     (rewind-stream _test-error-stream)
12932 #?     # }}}
12933     # check output
12934     (check-stream-equal _test-output-stream  ""  "F - test-read-from-stream-with-no-inouts: output should be empty")
12935     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt read-from-stream: too few inouts (2 required)"  "F - test-read-from-stream-with-no-inouts: error message")
12936     # check that stop(1) was called
12937     (check-ints-equal *(edx+4) 2 "F - test-read-from-stream-with-no-inouts: exit status")
12938     # don't restore from ebp
12939     81 0/subop/add %esp 8/imm32
12940     # . epilogue
12941     5d/pop-to-ebp
12942     c3/return
12944 test-read-from-stream-with-too-few-inouts:
12945     # . prologue
12946     55/push-ebp
12947     89/<- %ebp 4/r32/esp
12948     # setup
12949     (clear-stream _test-input-stream)
12950     (clear-stream $_test-input-buffered-file->buffer)
12951     (clear-stream _test-output-stream)
12952     (clear-stream $_test-output-buffered-file->buffer)
12953     (clear-stream _test-error-stream)
12954     (clear-stream $_test-error-buffered-file->buffer)
12955     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
12956     68/push 0/imm32
12957     68/push 0/imm32
12958     89/<- %edx 4/r32/esp
12959     (tailor-exit-descriptor %edx 0x10)
12960     #
12961     (write _test-input-stream "fn foo {\n")
12962     (write _test-input-stream "  var a: (addr stream int)\n")
12963     (write _test-input-stream "  read-from-stream a\n")
12964     (write _test-input-stream "}\n")
12965     # convert
12966     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
12967     # registers except esp clobbered at this point
12968     # restore ed
12969     89/<- %edx 4/r32/esp
12970     (flush _test-output-buffered-file)
12971     (flush _test-error-buffered-file)
12972 #?     # dump _test-error-stream {{{
12973 #?     (write 2 "^")
12974 #?     (write-stream 2 _test-error-stream)
12975 #?     (write 2 "$\n")
12976 #?     (rewind-stream _test-error-stream)
12977 #?     # }}}
12978     # check output
12979     (check-stream-equal _test-output-stream  ""  "F - test-read-from-stream-with-too-few-inouts: output should be empty")
12980     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt read-from-stream: too few inouts (2 required)"  "F - test-read-from-stream-with-too-few-inouts: error message")
12981     # check that stop(1) was called
12982     (check-ints-equal *(edx+4) 2 "F - test-read-from-stream-with-too-few-inouts: exit status")
12983     # don't restore from ebp
12984     81 0/subop/add %esp 8/imm32
12985     # . epilogue
12986     5d/pop-to-ebp
12987     c3/return
12989 test-read-from-stream-with-too-many-inouts:
12990     # . prologue
12991     55/push-ebp
12992     89/<- %ebp 4/r32/esp
12993     # setup
12994     (clear-stream _test-input-stream)
12995     (clear-stream $_test-input-buffered-file->buffer)
12996     (clear-stream _test-output-stream)
12997     (clear-stream $_test-output-buffered-file->buffer)
12998     (clear-stream _test-error-stream)
12999     (clear-stream $_test-error-buffered-file->buffer)
13000     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
13001     68/push 0/imm32
13002     68/push 0/imm32
13003     89/<- %edx 4/r32/esp
13004     (tailor-exit-descriptor %edx 0x10)
13005     #
13006     (write _test-input-stream "fn foo {\n")
13007     (write _test-input-stream "  var a: (addr stream int)\n")
13008     (write _test-input-stream "  var b: (addr int)\n")
13009     (write _test-input-stream "  read-from-stream a, b, 0\n")
13010     (write _test-input-stream "}\n")
13011     # convert
13012     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
13013     # registers except esp clobbered at this point
13014     # restore ed
13015     89/<- %edx 4/r32/esp
13016     (flush _test-output-buffered-file)
13017     (flush _test-error-buffered-file)
13018 #?     # dump _test-error-stream {{{
13019 #?     (write 2 "^")
13020 #?     (write-stream 2 _test-error-stream)
13021 #?     (write 2 "$\n")
13022 #?     (rewind-stream _test-error-stream)
13023 #?     # }}}
13024     # check output
13025     (check-stream-equal _test-output-stream  ""  "F - test-read-from-stream-with-too-many-inouts: output should be empty")
13026     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt read-from-stream: too many inouts (2 required)"  "F - test-read-from-stream-with-too-many-inouts: error message")
13027     # check that stop(1) was called
13028     (check-ints-equal *(edx+4) 2 "F - test-read-from-stream-with-too-many-inouts: exit status")
13029     # don't restore from ebp
13030     81 0/subop/add %esp 8/imm32
13031     # . epilogue
13032     5d/pop-to-ebp
13033     c3/return
13035 test-read-from-stream-with-output:
13036     # . prologue
13037     55/push-ebp
13038     89/<- %ebp 4/r32/esp
13039     # setup
13040     (clear-stream _test-input-stream)
13041     (clear-stream $_test-input-buffered-file->buffer)
13042     (clear-stream _test-output-stream)
13043     (clear-stream $_test-output-buffered-file->buffer)
13044     (clear-stream _test-error-stream)
13045     (clear-stream $_test-error-buffered-file->buffer)
13046     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
13047     68/push 0/imm32
13048     68/push 0/imm32
13049     89/<- %edx 4/r32/esp
13050     (tailor-exit-descriptor %edx 0x10)
13051     #
13052     (write _test-input-stream "fn foo {\n")
13053     (write _test-input-stream "  var a: (addr stream int)\n")
13054     (write _test-input-stream "  var b/eax: (addr int) <- copy 0\n")
13055     (write _test-input-stream "  b <- read-from-stream a, b\n")
13056     (write _test-input-stream "}\n")
13057     # convert
13058     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
13059     # registers except esp clobbered at this point
13060     # restore ed
13061     89/<- %edx 4/r32/esp
13062     (flush _test-output-buffered-file)
13063     (flush _test-error-buffered-file)
13064 #?     # dump _test-error-stream {{{
13065 #?     (write 2 "^")
13066 #?     (write-stream 2 _test-error-stream)
13067 #?     (write 2 "$\n")
13068 #?     (rewind-stream _test-error-stream)
13069 #?     # }}}
13070     # check output
13071     (check-stream-equal _test-output-stream  ""  "F - test-read-from-stream-with-output: output should be empty")
13072     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt read-from-stream: unexpected output"  "F - test-read-from-stream-with-output: error message")
13073     # check that stop(1) was called
13074     (check-ints-equal *(edx+4) 2 "F - test-read-from-stream-with-output: exit status")
13075     # don't restore from ebp
13076     81 0/subop/add %esp 8/imm32
13077     # . epilogue
13078     5d/pop-to-ebp
13079     c3/return
13081 test-convert-write-to-stream:
13082     # . prologue
13083     55/push-ebp
13084     89/<- %ebp 4/r32/esp
13085     # setup
13086     (clear-stream _test-input-stream)
13087     (clear-stream $_test-input-buffered-file->buffer)
13088     (clear-stream _test-output-stream)
13089     (clear-stream $_test-output-buffered-file->buffer)
13090     #
13091     (write _test-input-stream "fn foo {\n")
13092     (write _test-input-stream "  var s/esi: (addr stream int) <- copy 0\n")
13093     (write _test-input-stream "  var o/ecx: (addr int) <- copy 0\n")
13094     (write _test-input-stream "  write-to-stream s, o\n")
13095     (write _test-input-stream "}\n")
13096     # convert
13097     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
13098     # registers except esp clobbered at this point
13099     # restore ed
13100     89/<- %edx 4/r32/esp
13101     (flush _test-output-buffered-file)
13102     (flush _test-error-buffered-file)
13103 #?     # dump _test-output-stream {{{
13104 #?     (write 2 "^")
13105 #?     (write-stream 2 _test-output-stream)
13106 #?     (write 2 "$\n")
13107 #?     (rewind-stream _test-output-stream)
13108 #?     # }}}
13109     # check output
13110     (check-next-stream-line-equal _test-output-stream "foo:"                            "F - test-convert-write-to-stream/0")
13111     (check-next-stream-line-equal _test-output-stream "  # . prologue"                  "F - test-convert-write-to-stream/1")
13112     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                   "F - test-convert-write-to-stream/2")
13113     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"          "F - test-convert-write-to-stream/3")
13114     (check-next-stream-line-equal _test-output-stream "  {"                             "F - test-convert-write-to-stream/4")
13115     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"           "F - test-convert-write-to-stream/5")
13116     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %esi"        "F - test-convert-write-to-stream/6")
13117     (check-next-stream-line-equal _test-output-stream "    be/copy-to-esi 0/imm32"      "F - test-convert-write-to-stream/7")
13118     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"        "F - test-convert-write-to-stream/8")
13119     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"      "F - test-convert-write-to-stream/9")
13120     (check-next-stream-line-equal _test-output-stream "    (write-to-stream %esi %ecx 0x00000004)"  "F - test-convert-write-to-stream/10")
13121     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"         "F - test-convert-write-to-stream/11")
13122     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %esi"         "F - test-convert-write-to-stream/12")
13123     (check-next-stream-line-equal _test-output-stream "  }"                             "F - test-convert-write-to-stream/13")
13124     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"          "F - test-convert-write-to-stream/14")
13125     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                  "F - test-convert-write-to-stream/15")
13126     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"          "F - test-convert-write-to-stream/16")
13127     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                 "F - test-convert-write-to-stream/17")
13128     (check-next-stream-line-equal _test-output-stream "  c3/return"                     "F - test-convert-write-to-stream/18")
13129     # . epilogue
13130     89/<- %esp 5/r32/ebp
13131     5d/pop-to-ebp
13132     c3/return
13134 test-convert-write-to-stream-with-correct-payload-size:
13135     # . prologue
13136     55/push-ebp
13137     89/<- %ebp 4/r32/esp
13138     # setup
13139     (clear-stream _test-input-stream)
13140     (clear-stream $_test-input-buffered-file->buffer)
13141     (clear-stream _test-output-stream)
13142     (clear-stream $_test-output-buffered-file->buffer)
13143     #
13144     (write _test-input-stream "fn foo {\n")
13145     (write _test-input-stream "  var s/esi: (addr stream handle int) <- copy 0\n")
13146     (write _test-input-stream "  var o/ecx: (addr handle int) <- copy 0\n")
13147     (write _test-input-stream "  write-to-stream s, o\n")
13148     (write _test-input-stream "}\n")
13149     # convert
13150     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
13151     # registers except esp clobbered at this point
13152     # restore ed
13153     89/<- %edx 4/r32/esp
13154     (flush _test-output-buffered-file)
13155     (flush _test-error-buffered-file)
13156 #?     # dump _test-output-stream {{{
13157 #?     (write 2 "^")
13158 #?     (write-stream 2 _test-output-stream)
13159 #?     (write 2 "$\n")
13160 #?     (rewind-stream _test-output-stream)
13161 #?     # }}}
13162     # check output
13163     (check-next-stream-line-equal _test-output-stream "foo:"                            "F - test-convert-write-to-stream-with-correct-payload-size/0")
13164     (check-next-stream-line-equal _test-output-stream "  # . prologue"                  "F - test-convert-write-to-stream-with-correct-payload-size/1")
13165     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                   "F - test-convert-write-to-stream-with-correct-payload-size/2")
13166     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"          "F - test-convert-write-to-stream-with-correct-payload-size/3")
13167     (check-next-stream-line-equal _test-output-stream "  {"                             "F - test-convert-write-to-stream-with-correct-payload-size/4")
13168     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"           "F - test-convert-write-to-stream-with-correct-payload-size/5")
13169     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %esi"        "F - test-convert-write-to-stream-with-correct-payload-size/6")
13170     (check-next-stream-line-equal _test-output-stream "    be/copy-to-esi 0/imm32"      "F - test-convert-write-to-stream-with-correct-payload-size/7")
13171     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"        "F - test-convert-write-to-stream-with-correct-payload-size/8")
13172     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"      "F - test-convert-write-to-stream-with-correct-payload-size/9")
13173     (check-next-stream-line-equal _test-output-stream "    (write-to-stream %esi %ecx 0x00000008)"  "F - test-convert-write-to-stream-with-correct-payload-size/10")
13174     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"         "F - test-convert-write-to-stream-with-correct-payload-size/11")
13175     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %esi"         "F - test-convert-write-to-stream-with-correct-payload-size/12")
13176     (check-next-stream-line-equal _test-output-stream "  }"                             "F - test-convert-write-to-stream-with-correct-payload-size/13")
13177     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"          "F - test-convert-write-to-stream-with-correct-payload-size/14")
13178     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                  "F - test-convert-write-to-stream-with-correct-payload-size/15")
13179     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"          "F - test-convert-write-to-stream-with-correct-payload-size/16")
13180     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                 "F - test-convert-write-to-stream-with-correct-payload-size/17")
13181     (check-next-stream-line-equal _test-output-stream "  c3/return"                     "F - test-convert-write-to-stream-with-correct-payload-size/18")
13182     # . epilogue
13183     89/<- %esp 5/r32/ebp
13184     5d/pop-to-ebp
13185     c3/return
13187 test-write-to-stream-with-non-stream-atom-base-type:
13188     # . prologue
13189     55/push-ebp
13190     89/<- %ebp 4/r32/esp
13191     # setup
13192     (clear-stream _test-input-stream)
13193     (clear-stream $_test-input-buffered-file->buffer)
13194     (clear-stream _test-output-stream)
13195     (clear-stream $_test-output-buffered-file->buffer)
13196     (clear-stream _test-error-stream)
13197     (clear-stream $_test-error-buffered-file->buffer)
13198     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
13199     68/push 0/imm32
13200     68/push 0/imm32
13201     89/<- %edx 4/r32/esp
13202     (tailor-exit-descriptor %edx 0x10)
13203     #
13204     (write _test-input-stream "fn foo {\n")
13205     (write _test-input-stream "  var a: int\n")
13206     (write _test-input-stream "  write-to-stream a, 0\n")
13207     (write _test-input-stream "}\n")
13208     # convert
13209     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
13210     # registers except esp clobbered at this point
13211     # restore ed
13212     89/<- %edx 4/r32/esp
13213     (flush _test-output-buffered-file)
13214     (flush _test-error-buffered-file)
13215 #?     # dump _test-error-stream {{{
13216 #?     (write 2 "^")
13217 #?     (write-stream 2 _test-error-stream)
13218 #?     (write 2 "$\n")
13219 #?     (rewind-stream _test-error-stream)
13220 #?     # }}}
13221     # check output
13222     (check-stream-equal _test-output-stream  ""  "F - test-write-to-stream-with-non-stream-atom-base-type: output should be empty")
13223     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt write-to-stream: var 'a' must be an addr to a stream"  "F - test-write-to-stream-with-non-stream-atom-base-type: error message")
13224     # check that stop(1) was called
13225     (check-ints-equal *(edx+4) 2 "F - test-write-to-stream-with-non-stream-atom-base-type: exit status")
13226     # don't restore from ebp
13227     81 0/subop/add %esp 8/imm32
13228     # . epilogue
13229     5d/pop-to-ebp
13230     c3/return
13232 test-write-to-stream-with-non-stream-compound-base-type:
13233     # . prologue
13234     55/push-ebp
13235     89/<- %ebp 4/r32/esp
13236     # setup
13237     (clear-stream _test-input-stream)
13238     (clear-stream $_test-input-buffered-file->buffer)
13239     (clear-stream _test-output-stream)
13240     (clear-stream $_test-output-buffered-file->buffer)
13241     (clear-stream _test-error-stream)
13242     (clear-stream $_test-error-buffered-file->buffer)
13243     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
13244     68/push 0/imm32
13245     68/push 0/imm32
13246     89/<- %edx 4/r32/esp
13247     (tailor-exit-descriptor %edx 0x10)
13248     #
13249     (write _test-input-stream "fn foo {\n")
13250     (write _test-input-stream "  var a: (handle int)\n")
13251     (write _test-input-stream "  write-to-stream a, 0\n")
13252     (write _test-input-stream "}\n")
13253     # convert
13254     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
13255     # registers except esp clobbered at this point
13256     # restore ed
13257     89/<- %edx 4/r32/esp
13258     (flush _test-output-buffered-file)
13259     (flush _test-error-buffered-file)
13260 #?     # dump _test-error-stream {{{
13261 #?     (write 2 "^")
13262 #?     (write-stream 2 _test-error-stream)
13263 #?     (write 2 "$\n")
13264 #?     (rewind-stream _test-error-stream)
13265 #?     # }}}
13266     # check output
13267     (check-stream-equal _test-output-stream  ""  "F - test-write-to-stream-with-non-stream-compound-base-type: output should be empty")
13268     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt write-to-stream: var 'a' must be an addr to a stream"  "F - test-write-to-stream-with-non-stream-compound-base-type: error message")
13269     # check that stop(1) was called
13270     (check-ints-equal *(edx+4) 2 "F - test-write-to-stream-with-non-stream-compound-base-type: exit status")
13271     # don't restore from ebp
13272     81 0/subop/add %esp 8/imm32
13273     # . epilogue
13274     5d/pop-to-ebp
13275     c3/return
13277 test-write-to-stream-with-non-stream-compound-base-type-2:
13278     # . prologue
13279     55/push-ebp
13280     89/<- %ebp 4/r32/esp
13281     # setup
13282     (clear-stream _test-input-stream)
13283     (clear-stream $_test-input-buffered-file->buffer)
13284     (clear-stream _test-output-stream)
13285     (clear-stream $_test-output-buffered-file->buffer)
13286     (clear-stream _test-error-stream)
13287     (clear-stream $_test-error-buffered-file->buffer)
13288     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
13289     68/push 0/imm32
13290     68/push 0/imm32
13291     89/<- %edx 4/r32/esp
13292     (tailor-exit-descriptor %edx 0x10)
13293     #
13294     (write _test-input-stream "fn foo {\n")
13295     (write _test-input-stream "  var a: (addr int)\n")
13296     (write _test-input-stream "  write-to-stream a, 0\n")
13297     (write _test-input-stream "}\n")
13298     # convert
13299     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
13300     # registers except esp clobbered at this point
13301     # restore ed
13302     89/<- %edx 4/r32/esp
13303     (flush _test-output-buffered-file)
13304     (flush _test-error-buffered-file)
13305 #?     # dump _test-error-stream {{{
13306 #?     (write 2 "^")
13307 #?     (write-stream 2 _test-error-stream)
13308 #?     (write 2 "$\n")
13309 #?     (rewind-stream _test-error-stream)
13310 #?     # }}}
13311     # check output
13312     (check-stream-equal _test-output-stream  ""  "F - test-write-to-stream-with-non-stream-compound-base-type-2: output should be empty")
13313     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt write-to-stream: var 'a' must be an addr to a stream"  "F - test-write-to-stream-with-non-stream-compound-base-type-2: error message")
13314     # check that stop(1) was called
13315     (check-ints-equal *(edx+4) 2 "F - test-write-to-stream-with-non-stream-compound-base-type-2: exit status")
13316     # don't restore from ebp
13317     81 0/subop/add %esp 8/imm32
13318     # . epilogue
13319     5d/pop-to-ebp
13320     c3/return
13322 test-write-to-stream-with-stream-atom-base-type:
13323     # . prologue
13324     55/push-ebp
13325     89/<- %ebp 4/r32/esp
13326     # setup
13327     (clear-stream _test-input-stream)
13328     (clear-stream $_test-input-buffered-file->buffer)
13329     (clear-stream _test-output-stream)
13330     (clear-stream $_test-output-buffered-file->buffer)
13331     (clear-stream _test-error-stream)
13332     (clear-stream $_test-error-buffered-file->buffer)
13333     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
13334     68/push 0/imm32
13335     68/push 0/imm32
13336     89/<- %edx 4/r32/esp
13337     (tailor-exit-descriptor %edx 0x10)
13338     #
13339     (write _test-input-stream "fn foo {\n")
13340     (write _test-input-stream "  var a: stream\n")
13341     (write _test-input-stream "  write-to-stream a, 0\n")
13342     (write _test-input-stream "}\n")
13343     # convert
13344     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
13345     # registers except esp clobbered at this point
13346     # restore ed
13347     89/<- %edx 4/r32/esp
13348     (flush _test-output-buffered-file)
13349     (flush _test-error-buffered-file)
13350 #?     # dump _test-error-stream {{{
13351 #?     (write 2 "^")
13352 #?     (write-stream 2 _test-error-stream)
13353 #?     (write 2 "$\n")
13354 #?     (rewind-stream _test-error-stream)
13355 #?     # }}}
13356     # check output
13357     (check-stream-equal _test-output-stream  ""  "F - test-write-to-stream-with-stream-atom-base-type: output should be empty")
13358     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt write-to-stream: var 'a' must be an addr to a stream"  "F - test-write-to-stream-with-stream-atom-base-type: error message")
13359     # check that stop(1) was called
13360     (check-ints-equal *(edx+4) 2 "F - test-write-to-stream-with-stream-atom-base-type: exit status")
13361     # don't restore from ebp
13362     81 0/subop/add %esp 8/imm32
13363     # . epilogue
13364     5d/pop-to-ebp
13365     c3/return
13367 test-write-to-stream-with-wrong-index-type:
13368     # . prologue
13369     55/push-ebp
13370     89/<- %ebp 4/r32/esp
13371     # setup
13372     (clear-stream _test-input-stream)
13373     (clear-stream $_test-input-buffered-file->buffer)
13374     (clear-stream _test-output-stream)
13375     (clear-stream $_test-output-buffered-file->buffer)
13376     (clear-stream _test-error-stream)
13377     (clear-stream $_test-error-buffered-file->buffer)
13378     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
13379     68/push 0/imm32
13380     68/push 0/imm32
13381     89/<- %edx 4/r32/esp
13382     (tailor-exit-descriptor %edx 0x10)
13383     #
13384     (write _test-input-stream "fn foo {\n")
13385     (write _test-input-stream "  var a/eax: (addr stream int) <- copy 0\n")
13386     (write _test-input-stream "  var b: boolean\n")
13387     (write _test-input-stream "  write-to-stream a, b\n")
13388     (write _test-input-stream "}\n")
13389     # convert
13390     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
13391     # registers except esp clobbered at this point
13392     # restore ed
13393     89/<- %edx 4/r32/esp
13394     (flush _test-output-buffered-file)
13395     (flush _test-error-buffered-file)
13396 #?     # dump _test-error-stream {{{
13397 #?     (write 2 "^")
13398 #?     (write-stream 2 _test-error-stream)
13399 #?     (write 2 "$\n")
13400 #?     (rewind-stream _test-error-stream)
13401 #?     # }}}
13402     # check output
13403     (check-stream-equal _test-output-stream  ""  "F - test-write-to-stream-with-wrong-index-type: output should be empty")
13404     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt write-to-stream: target 'b' must be an addr"  "F - test-write-to-stream-with-wrong-index-type: error message")
13405     # check that stop(1) was called
13406     (check-ints-equal *(edx+4) 2 "F - test-write-to-stream-with-wrong-index-type: exit status")
13407     # don't restore from ebp
13408     81 0/subop/add %esp 8/imm32
13409     # . epilogue
13410     5d/pop-to-ebp
13411     c3/return
13413 test-write-to-stream-with-no-inouts:
13414     # . prologue
13415     55/push-ebp
13416     89/<- %ebp 4/r32/esp
13417     # setup
13418     (clear-stream _test-input-stream)
13419     (clear-stream $_test-input-buffered-file->buffer)
13420     (clear-stream _test-output-stream)
13421     (clear-stream $_test-output-buffered-file->buffer)
13422     (clear-stream _test-error-stream)
13423     (clear-stream $_test-error-buffered-file->buffer)
13424     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
13425     68/push 0/imm32
13426     68/push 0/imm32
13427     89/<- %edx 4/r32/esp
13428     (tailor-exit-descriptor %edx 0x10)
13429     #
13430     (write _test-input-stream "fn foo {\n")
13431     (write _test-input-stream "  write-to-stream\n")
13432     (write _test-input-stream "}\n")
13433     # convert
13434     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
13435     # registers except esp clobbered at this point
13436     # restore ed
13437     89/<- %edx 4/r32/esp
13438     (flush _test-output-buffered-file)
13439     (flush _test-error-buffered-file)
13440 #?     # dump _test-error-stream {{{
13441 #?     (write 2 "^")
13442 #?     (write-stream 2 _test-error-stream)
13443 #?     (write 2 "$\n")
13444 #?     (rewind-stream _test-error-stream)
13445 #?     # }}}
13446     # check output
13447     (check-stream-equal _test-output-stream  ""  "F - test-write-to-stream-with-no-inouts: output should be empty")
13448     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt write-to-stream: too few inouts (2 required)"  "F - test-write-to-stream-with-no-inouts: error message")
13449     # check that stop(1) was called
13450     (check-ints-equal *(edx+4) 2 "F - test-write-to-stream-with-no-inouts: exit status")
13451     # don't restore from ebp
13452     81 0/subop/add %esp 8/imm32
13453     # . epilogue
13454     5d/pop-to-ebp
13455     c3/return
13457 test-write-to-stream-with-too-few-inouts:
13458     # . prologue
13459     55/push-ebp
13460     89/<- %ebp 4/r32/esp
13461     # setup
13462     (clear-stream _test-input-stream)
13463     (clear-stream $_test-input-buffered-file->buffer)
13464     (clear-stream _test-output-stream)
13465     (clear-stream $_test-output-buffered-file->buffer)
13466     (clear-stream _test-error-stream)
13467     (clear-stream $_test-error-buffered-file->buffer)
13468     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
13469     68/push 0/imm32
13470     68/push 0/imm32
13471     89/<- %edx 4/r32/esp
13472     (tailor-exit-descriptor %edx 0x10)
13473     #
13474     (write _test-input-stream "fn foo {\n")
13475     (write _test-input-stream "  var a: (addr stream int)\n")
13476     (write _test-input-stream "  write-to-stream a\n")
13477     (write _test-input-stream "}\n")
13478     # convert
13479     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
13480     # registers except esp clobbered at this point
13481     # restore ed
13482     89/<- %edx 4/r32/esp
13483     (flush _test-output-buffered-file)
13484     (flush _test-error-buffered-file)
13485 #?     # dump _test-error-stream {{{
13486 #?     (write 2 "^")
13487 #?     (write-stream 2 _test-error-stream)
13488 #?     (write 2 "$\n")
13489 #?     (rewind-stream _test-error-stream)
13490 #?     # }}}
13491     # check output
13492     (check-stream-equal _test-output-stream  ""  "F - test-write-to-stream-with-too-few-inouts: output should be empty")
13493     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt write-to-stream: too few inouts (2 required)"  "F - test-write-to-stream-with-too-few-inouts: error message")
13494     # check that stop(1) was called
13495     (check-ints-equal *(edx+4) 2 "F - test-write-to-stream-with-too-few-inouts: exit status")
13496     # don't restore from ebp
13497     81 0/subop/add %esp 8/imm32
13498     # . epilogue
13499     5d/pop-to-ebp
13500     c3/return
13502 test-write-to-stream-with-too-many-inouts:
13503     # . prologue
13504     55/push-ebp
13505     89/<- %ebp 4/r32/esp
13506     # setup
13507     (clear-stream _test-input-stream)
13508     (clear-stream $_test-input-buffered-file->buffer)
13509     (clear-stream _test-output-stream)
13510     (clear-stream $_test-output-buffered-file->buffer)
13511     (clear-stream _test-error-stream)
13512     (clear-stream $_test-error-buffered-file->buffer)
13513     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
13514     68/push 0/imm32
13515     68/push 0/imm32
13516     89/<- %edx 4/r32/esp
13517     (tailor-exit-descriptor %edx 0x10)
13518     #
13519     (write _test-input-stream "fn foo {\n")
13520     (write _test-input-stream "  var a: (addr stream int)\n")
13521     (write _test-input-stream "  var b: (addr int)\n")
13522     (write _test-input-stream "  write-to-stream a, b, 0\n")
13523     (write _test-input-stream "}\n")
13524     # convert
13525     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
13526     # registers except esp clobbered at this point
13527     # restore ed
13528     89/<- %edx 4/r32/esp
13529     (flush _test-output-buffered-file)
13530     (flush _test-error-buffered-file)
13531 #?     # dump _test-error-stream {{{
13532 #?     (write 2 "^")
13533 #?     (write-stream 2 _test-error-stream)
13534 #?     (write 2 "$\n")
13535 #?     (rewind-stream _test-error-stream)
13536 #?     # }}}
13537     # check output
13538     (check-stream-equal _test-output-stream  ""  "F - test-write-to-stream-with-too-many-inouts: output should be empty")
13539     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt write-to-stream: too many inouts (2 required)"  "F - test-write-to-stream-with-too-many-inouts: error message")
13540     # check that stop(1) was called
13541     (check-ints-equal *(edx+4) 2 "F - test-write-to-stream-with-too-many-inouts: exit status")
13542     # don't restore from ebp
13543     81 0/subop/add %esp 8/imm32
13544     # . epilogue
13545     5d/pop-to-ebp
13546     c3/return
13548 test-write-to-stream-with-output:
13549     # . prologue
13550     55/push-ebp
13551     89/<- %ebp 4/r32/esp
13552     # setup
13553     (clear-stream _test-input-stream)
13554     (clear-stream $_test-input-buffered-file->buffer)
13555     (clear-stream _test-output-stream)
13556     (clear-stream $_test-output-buffered-file->buffer)
13557     (clear-stream _test-error-stream)
13558     (clear-stream $_test-error-buffered-file->buffer)
13559     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
13560     68/push 0/imm32
13561     68/push 0/imm32
13562     89/<- %edx 4/r32/esp
13563     (tailor-exit-descriptor %edx 0x10)
13564     #
13565     (write _test-input-stream "fn foo {\n")
13566     (write _test-input-stream "  var a: (addr stream int)\n")
13567     (write _test-input-stream "  var b/eax: (addr int) <- copy 0\n")
13568     (write _test-input-stream "  b <- write-to-stream a, b\n")
13569     (write _test-input-stream "}\n")
13570     # convert
13571     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
13572     # registers except esp clobbered at this point
13573     # restore ed
13574     89/<- %edx 4/r32/esp
13575     (flush _test-output-buffered-file)
13576     (flush _test-error-buffered-file)
13577 #?     # dump _test-error-stream {{{
13578 #?     (write 2 "^")
13579 #?     (write-stream 2 _test-error-stream)
13580 #?     (write 2 "$\n")
13581 #?     (rewind-stream _test-error-stream)
13582 #?     # }}}
13583     # check output
13584     (check-stream-equal _test-output-stream  ""  "F - test-write-to-stream-with-output: output should be empty")
13585     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt write-to-stream: unexpected output"  "F - test-write-to-stream-with-output: error message")
13586     # check that stop(1) was called
13587     (check-ints-equal *(edx+4) 2 "F - test-write-to-stream-with-output: exit status")
13588     # don't restore from ebp
13589     81 0/subop/add %esp 8/imm32
13590     # . epilogue
13591     5d/pop-to-ebp
13592     c3/return
13594 test-length-with-non-array-atom-base-type:
13595     # . prologue
13596     55/push-ebp
13597     89/<- %ebp 4/r32/esp
13598     # setup
13599     (clear-stream _test-input-stream)
13600     (clear-stream $_test-input-buffered-file->buffer)
13601     (clear-stream _test-output-stream)
13602     (clear-stream $_test-output-buffered-file->buffer)
13603     (clear-stream _test-error-stream)
13604     (clear-stream $_test-error-buffered-file->buffer)
13605     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
13606     68/push 0/imm32
13607     68/push 0/imm32
13608     89/<- %edx 4/r32/esp
13609     (tailor-exit-descriptor %edx 0x10)
13610     #
13611     (write _test-input-stream "fn foo {\n")
13612     (write _test-input-stream "  var a: int\n")
13613     (write _test-input-stream "  var c/ecx: int <- length a\n")
13614     (write _test-input-stream "}\n")
13615     # convert
13616     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
13617     # registers except esp clobbered at this point
13618     # restore ed
13619     89/<- %edx 4/r32/esp
13620     (flush _test-output-buffered-file)
13621     (flush _test-error-buffered-file)
13622 #?     # dump _test-error-stream {{{
13623 #?     (write 2 "^")
13624 #?     (write-stream 2 _test-error-stream)
13625 #?     (write 2 "$\n")
13626 #?     (rewind-stream _test-error-stream)
13627 #?     # }}}
13628     # check output
13629     (check-stream-equal _test-output-stream  ""  "F - test-length-with-non-array-atom-base-type: output should be empty")
13630     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt length: var 'a' is not an array"  "F - test-length-with-non-array-atom-base-type: error message")
13631     # check that stop(1) was called
13632     (check-ints-equal *(edx+4) 2 "F - test-length-with-non-array-atom-base-type: exit status")
13633     # don't restore from ebp
13634     81 0/subop/add %esp 8/imm32
13635     # . epilogue
13636     5d/pop-to-ebp
13637     c3/return
13639 test-length-with-non-array-compound-base-type:
13640     # . prologue
13641     55/push-ebp
13642     89/<- %ebp 4/r32/esp
13643     # setup
13644     (clear-stream _test-input-stream)
13645     (clear-stream $_test-input-buffered-file->buffer)
13646     (clear-stream _test-output-stream)
13647     (clear-stream $_test-output-buffered-file->buffer)
13648     (clear-stream _test-error-stream)
13649     (clear-stream $_test-error-buffered-file->buffer)
13650     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
13651     68/push 0/imm32
13652     68/push 0/imm32
13653     89/<- %edx 4/r32/esp
13654     (tailor-exit-descriptor %edx 0x10)
13655     #
13656     (write _test-input-stream "fn foo {\n")
13657     (write _test-input-stream "  var a: (handle int)\n")
13658     (write _test-input-stream "  var c/ecx: (addr int) <- length a, 0\n")
13659     (write _test-input-stream "}\n")
13660     # convert
13661     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
13662     # registers except esp clobbered at this point
13663     # restore ed
13664     89/<- %edx 4/r32/esp
13665     (flush _test-output-buffered-file)
13666     (flush _test-error-buffered-file)
13667 #?     # dump _test-error-stream {{{
13668 #?     (write 2 "^")
13669 #?     (write-stream 2 _test-error-stream)
13670 #?     (write 2 "$\n")
13671 #?     (rewind-stream _test-error-stream)
13672 #?     # }}}
13673     # check output
13674     (check-stream-equal _test-output-stream  ""  "F - test-length-with-non-array-compound-base-type: output should be empty")
13675     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt length: var 'a' is not an array"  "F - test-length-with-non-array-compound-base-type: error message")
13676     # check that stop(1) was called
13677     (check-ints-equal *(edx+4) 2 "F - test-length-with-non-array-compound-base-type: exit status")
13678     # don't restore from ebp
13679     81 0/subop/add %esp 8/imm32
13680     # . epilogue
13681     5d/pop-to-ebp
13682     c3/return
13684 test-length-with-non-array-compound-base-type-2:
13685     # . prologue
13686     55/push-ebp
13687     89/<- %ebp 4/r32/esp
13688     # setup
13689     (clear-stream _test-input-stream)
13690     (clear-stream $_test-input-buffered-file->buffer)
13691     (clear-stream _test-output-stream)
13692     (clear-stream $_test-output-buffered-file->buffer)
13693     (clear-stream _test-error-stream)
13694     (clear-stream $_test-error-buffered-file->buffer)
13695     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
13696     68/push 0/imm32
13697     68/push 0/imm32
13698     89/<- %edx 4/r32/esp
13699     (tailor-exit-descriptor %edx 0x10)
13700     #
13701     (write _test-input-stream "fn foo {\n")
13702     (write _test-input-stream "  var a: (addr int)\n")
13703     (write _test-input-stream "  var c/ecx: (addr int) <- length a, 0\n")
13704     (write _test-input-stream "}\n")
13705     # convert
13706     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
13707     # registers except esp clobbered at this point
13708     # restore ed
13709     89/<- %edx 4/r32/esp
13710     (flush _test-output-buffered-file)
13711     (flush _test-error-buffered-file)
13712 #?     # dump _test-error-stream {{{
13713 #?     (write 2 "^")
13714 #?     (write-stream 2 _test-error-stream)
13715 #?     (write 2 "$\n")
13716 #?     (rewind-stream _test-error-stream)
13717 #?     # }}}
13718     # check output
13719     (check-stream-equal _test-output-stream  ""  "F - test-length-with-non-array-compound-base-type-2: output should be empty")
13720     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt length: var 'a' is not an array"  "F - test-length-with-non-array-compound-base-type-2: error message")
13721     # check that stop(1) was called
13722     (check-ints-equal *(edx+4) 2 "F - test-length-with-non-array-compound-base-type-2: exit status")
13723     # don't restore from ebp
13724     81 0/subop/add %esp 8/imm32
13725     # . epilogue
13726     5d/pop-to-ebp
13727     c3/return
13729 test-length-with-array-atom-base-type:
13730     # . prologue
13731     55/push-ebp
13732     89/<- %ebp 4/r32/esp
13733     # setup
13734     (clear-stream _test-input-stream)
13735     (clear-stream $_test-input-buffered-file->buffer)
13736     (clear-stream _test-output-stream)
13737     (clear-stream $_test-output-buffered-file->buffer)
13738     (clear-stream _test-error-stream)
13739     (clear-stream $_test-error-buffered-file->buffer)
13740     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
13741     68/push 0/imm32
13742     68/push 0/imm32
13743     89/<- %edx 4/r32/esp
13744     (tailor-exit-descriptor %edx 0x10)
13745     #
13746     (write _test-input-stream "fn foo {\n")
13747     (write _test-input-stream "  var a: array\n")
13748     (write _test-input-stream "  var c/ecx: (addr int) <- length a\n")
13749     (write _test-input-stream "}\n")
13750     # convert
13751     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
13752     # registers except esp clobbered at this point
13753     # restore ed
13754     89/<- %edx 4/r32/esp
13755     (flush _test-output-buffered-file)
13756     (flush _test-error-buffered-file)
13757 #?     # dump _test-error-stream {{{
13758 #?     (write 2 "^")
13759 #?     (write-stream 2 _test-error-stream)
13760 #?     (write 2 "$\n")
13761 #?     (rewind-stream _test-error-stream)
13762 #?     # }}}
13763     # check output
13764     (check-stream-equal _test-output-stream  ""  "F - test-length-with-array-atom-base-type: output should be empty")
13765     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt length: array 'a' must specify the type of its elements"  "F - test-length-with-array-atom-base-type: error message")
13766     # check that stop(1) was called
13767     (check-ints-equal *(edx+4) 2 "F - test-length-with-array-atom-base-type: exit status")
13768     # don't restore from ebp
13769     81 0/subop/add %esp 8/imm32
13770     # . epilogue
13771     5d/pop-to-ebp
13772     c3/return
13774 test-length-with-addr-base-on-stack:
13775     # . prologue
13776     55/push-ebp
13777     89/<- %ebp 4/r32/esp
13778     # setup
13779     (clear-stream _test-input-stream)
13780     (clear-stream $_test-input-buffered-file->buffer)
13781     (clear-stream _test-output-stream)
13782     (clear-stream $_test-output-buffered-file->buffer)
13783     (clear-stream _test-error-stream)
13784     (clear-stream $_test-error-buffered-file->buffer)
13785     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
13786     68/push 0/imm32
13787     68/push 0/imm32
13788     89/<- %edx 4/r32/esp
13789     (tailor-exit-descriptor %edx 0x10)
13790     #
13791     (write _test-input-stream "fn foo {\n")
13792     (write _test-input-stream "  var a: (addr array int)\n")
13793     (write _test-input-stream "  var c/ecx: (addr int) <- length a\n")
13794     (write _test-input-stream "}\n")
13795     # convert
13796     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
13797     # registers except esp clobbered at this point
13798     # restore ed
13799     89/<- %edx 4/r32/esp
13800     (flush _test-output-buffered-file)
13801     (flush _test-error-buffered-file)
13802 #?     # dump _test-error-stream {{{
13803 #?     (write 2 "^")
13804 #?     (write-stream 2 _test-error-stream)
13805 #?     (write 2 "$\n")
13806 #?     (rewind-stream _test-error-stream)
13807 #?     # }}}
13808     # check output
13809     (check-stream-equal _test-output-stream  ""  "F - test-length-with-addr-base-on-stack: output should be empty")
13810     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt length: var 'a' is an addr to an array, and so must live in a register"  "F - test-length-with-addr-base-on-stack: error message")
13811     # check that stop(1) was called
13812     (check-ints-equal *(edx+4) 2 "F - test-length-with-addr-base-on-stack: exit status")
13813     # don't restore from ebp
13814     81 0/subop/add %esp 8/imm32
13815     # . epilogue
13816     5d/pop-to-ebp
13817     c3/return
13819 test-length-with-wrong-output-type:
13820     # . prologue
13821     55/push-ebp
13822     89/<- %ebp 4/r32/esp
13823     # setup
13824     (clear-stream _test-input-stream)
13825     (clear-stream $_test-input-buffered-file->buffer)
13826     (clear-stream _test-output-stream)
13827     (clear-stream $_test-output-buffered-file->buffer)
13828     (clear-stream _test-error-stream)
13829     (clear-stream $_test-error-buffered-file->buffer)
13830     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
13831     68/push 0/imm32
13832     68/push 0/imm32
13833     89/<- %edx 4/r32/esp
13834     (tailor-exit-descriptor %edx 0x10)
13835     #
13836     (write _test-input-stream "fn foo {\n")
13837     (write _test-input-stream "  var a/ebx: (addr array boolean) <- copy 0\n")
13838     (write _test-input-stream "  var o/edi: (addr int) <- length a\n")
13839     (write _test-input-stream "}\n")
13840     # convert
13841     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
13842     # registers except esp clobbered at this point
13843     # restore ed
13844     89/<- %edx 4/r32/esp
13845     (flush _test-output-buffered-file)
13846     (flush _test-error-buffered-file)
13847 #?     # dump _test-error-stream {{{
13848 #?     (write 2 "^")
13849 #?     (write-stream 2 _test-error-stream)
13850 #?     (write 2 "$\n")
13851 #?     (rewind-stream _test-error-stream)
13852 #?     # }}}
13853     # check output
13854     (check-stream-equal _test-output-stream  ""  "F - test-length-with-wrong-output-type: output should be empty")
13855     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt length: output 'o' does not have the right type"  "F - test-length-with-wrong-output-type: error message")
13856     # check that stop(1) was called
13857     (check-ints-equal *(edx+4) 2 "F - test-length-with-wrong-output-type: exit status")
13858     # don't restore from ebp
13859     81 0/subop/add %esp 8/imm32
13860     # . epilogue
13861     5d/pop-to-ebp
13862     c3/return
13864 test-length-with-wrong-output-compound-type:
13865     # . prologue
13866     55/push-ebp
13867     89/<- %ebp 4/r32/esp
13868     # setup
13869     (clear-stream _test-input-stream)
13870     (clear-stream $_test-input-buffered-file->buffer)
13871     (clear-stream _test-output-stream)
13872     (clear-stream $_test-output-buffered-file->buffer)
13873     (clear-stream _test-error-stream)
13874     (clear-stream $_test-error-buffered-file->buffer)
13875     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
13876     68/push 0/imm32
13877     68/push 0/imm32
13878     89/<- %edx 4/r32/esp
13879     (tailor-exit-descriptor %edx 0x10)
13880     #
13881     (write _test-input-stream "fn foo {\n")
13882     (write _test-input-stream "  var a/ebx: (addr array handle boolean) <- copy 0\n")
13883     (write _test-input-stream "  var o/edi: (addr handle int) <- length a\n")
13884     (write _test-input-stream "}\n")
13885     # convert
13886     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
13887     # registers except esp clobbered at this point
13888     # restore ed
13889     89/<- %edx 4/r32/esp
13890     (flush _test-output-buffered-file)
13891     (flush _test-error-buffered-file)
13892 #?     # dump _test-error-stream {{{
13893 #?     (write 2 "^")
13894 #?     (write-stream 2 _test-error-stream)
13895 #?     (write 2 "$\n")
13896 #?     (rewind-stream _test-error-stream)
13897 #?     # }}}
13898     # check output
13899     (check-stream-equal _test-output-stream  ""  "F - test-length-with-wrong-output-compound-type: output should be empty")
13900     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt length: output 'o' does not have the right type"  "F - test-length-with-wrong-output-compound-type: error message")
13901     # check that stop(1) was called
13902     (check-ints-equal *(edx+4) 2 "F - test-length-with-wrong-output-compound-type: exit status")
13903     # don't restore from ebp
13904     81 0/subop/add %esp 8/imm32
13905     # . epilogue
13906     5d/pop-to-ebp
13907     c3/return
13909 test-length-with-no-inouts:
13910     # . prologue
13911     55/push-ebp
13912     89/<- %ebp 4/r32/esp
13913     # setup
13914     (clear-stream _test-input-stream)
13915     (clear-stream $_test-input-buffered-file->buffer)
13916     (clear-stream _test-output-stream)
13917     (clear-stream $_test-output-buffered-file->buffer)
13918     (clear-stream _test-error-stream)
13919     (clear-stream $_test-error-buffered-file->buffer)
13920     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
13921     68/push 0/imm32
13922     68/push 0/imm32
13923     89/<- %edx 4/r32/esp
13924     (tailor-exit-descriptor %edx 0x10)
13925     #
13926     (write _test-input-stream "fn foo {\n")
13927     (write _test-input-stream "  var c/ecx: int <- length\n")
13928     (write _test-input-stream "}\n")
13929     # convert
13930     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
13931     # registers except esp clobbered at this point
13932     # restore ed
13933     89/<- %edx 4/r32/esp
13934     (flush _test-output-buffered-file)
13935     (flush _test-error-buffered-file)
13936 #?     # dump _test-error-stream {{{
13937 #?     (write 2 "^")
13938 #?     (write-stream 2 _test-error-stream)
13939 #?     (write 2 "$\n")
13940 #?     (rewind-stream _test-error-stream)
13941 #?     # }}}
13942     # check output
13943     (check-stream-equal _test-output-stream  ""  "F - test-length-with-no-inouts: output should be empty")
13944     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt length: too few inouts (1 required)"  "F - test-length-with-no-inouts: error message")
13945     # check that stop(1) was called
13946     (check-ints-equal *(edx+4) 2 "F - test-length-with-no-inouts: exit status")
13947     # don't restore from ebp
13948     81 0/subop/add %esp 8/imm32
13949     # . epilogue
13950     5d/pop-to-ebp
13951     c3/return
13953 test-length-with-too-many-inouts:
13954     # . prologue
13955     55/push-ebp
13956     89/<- %ebp 4/r32/esp
13957     # setup
13958     (clear-stream _test-input-stream)
13959     (clear-stream $_test-input-buffered-file->buffer)
13960     (clear-stream _test-output-stream)
13961     (clear-stream $_test-output-buffered-file->buffer)
13962     (clear-stream _test-error-stream)
13963     (clear-stream $_test-error-buffered-file->buffer)
13964     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
13965     68/push 0/imm32
13966     68/push 0/imm32
13967     89/<- %edx 4/r32/esp
13968     (tailor-exit-descriptor %edx 0x10)
13969     #
13970     (write _test-input-stream "fn foo {\n")
13971     (write _test-input-stream "  var a: (array int 3)\n")
13972     (write _test-input-stream "  var c/ecx: int <- length a, 0, 0\n")
13973     (write _test-input-stream "}\n")
13974     # convert
13975     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
13976     # registers except esp clobbered at this point
13977     # restore ed
13978     89/<- %edx 4/r32/esp
13979     (flush _test-output-buffered-file)
13980     (flush _test-error-buffered-file)
13981 #?     # dump _test-error-stream {{{
13982 #?     (write 2 "^")
13983 #?     (write-stream 2 _test-error-stream)
13984 #?     (write 2 "$\n")
13985 #?     (rewind-stream _test-error-stream)
13986 #?     # }}}
13987     # check output
13988     (check-stream-equal _test-output-stream  ""  "F - test-length-with-too-many-inouts: output should be empty")
13989     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt length: too many inouts (1 required)"  "F - test-length-with-too-many-inouts: error message")
13990     # check that stop(1) was called
13991     (check-ints-equal *(edx+4) 2 "F - test-length-with-too-many-inouts: exit status")
13992     # don't restore from ebp
13993     81 0/subop/add %esp 8/imm32
13994     # . epilogue
13995     5d/pop-to-ebp
13996     c3/return
13998 test-length-with-no-output:
13999     # . prologue
14000     55/push-ebp
14001     89/<- %ebp 4/r32/esp
14002     # setup
14003     (clear-stream _test-input-stream)
14004     (clear-stream $_test-input-buffered-file->buffer)
14005     (clear-stream _test-output-stream)
14006     (clear-stream $_test-output-buffered-file->buffer)
14007     (clear-stream _test-error-stream)
14008     (clear-stream $_test-error-buffered-file->buffer)
14009     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
14010     68/push 0/imm32
14011     68/push 0/imm32
14012     89/<- %edx 4/r32/esp
14013     (tailor-exit-descriptor %edx 0x10)
14014     #
14015     (write _test-input-stream "fn foo {\n")
14016     (write _test-input-stream "  var a: (array int 3)\n")
14017     (write _test-input-stream "  length a\n")
14018     (write _test-input-stream "}\n")
14019     # convert
14020     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
14021     # registers except esp clobbered at this point
14022     # restore ed
14023     89/<- %edx 4/r32/esp
14024     (flush _test-output-buffered-file)
14025     (flush _test-error-buffered-file)
14026 #?     # dump _test-error-stream {{{
14027 #?     (write 2 "^")
14028 #?     (write-stream 2 _test-error-stream)
14029 #?     (write 2 "$\n")
14030 #?     (rewind-stream _test-error-stream)
14031 #?     # }}}
14032     # check output
14033     (check-stream-equal _test-output-stream  ""  "F - test-length-with-no-output: output should be empty")
14034     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt length: must have an output"  "F - test-length-with-no-output: error message")
14035     # check that stop(1) was called
14036     (check-ints-equal *(edx+4) 2 "F - test-length-with-no-output: exit status")
14037     # don't restore from ebp
14038     81 0/subop/add %esp 8/imm32
14039     # . epilogue
14040     5d/pop-to-ebp
14041     c3/return
14043 test-length-with-too-many-outputs:
14044     # . prologue
14045     55/push-ebp
14046     89/<- %ebp 4/r32/esp
14047     # setup
14048     (clear-stream _test-input-stream)
14049     (clear-stream $_test-input-buffered-file->buffer)
14050     (clear-stream _test-output-stream)
14051     (clear-stream $_test-output-buffered-file->buffer)
14052     (clear-stream _test-error-stream)
14053     (clear-stream $_test-error-buffered-file->buffer)
14054     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
14055     68/push 0/imm32
14056     68/push 0/imm32
14057     89/<- %edx 4/r32/esp
14058     (tailor-exit-descriptor %edx 0x10)
14059     #
14060     (write _test-input-stream "fn foo {\n")
14061     (write _test-input-stream "  var a: (array int 3)\n")
14062     (write _test-input-stream "  var b/eax: int <- copy 0\n")
14063     (write _test-input-stream "  var c/ecx: int <- copy 0\n")
14064     (write _test-input-stream "  b, c <- length a\n")
14065     (write _test-input-stream "}\n")
14066     # convert
14067     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
14068     # registers except esp clobbered at this point
14069     # restore ed
14070     89/<- %edx 4/r32/esp
14071     (flush _test-output-buffered-file)
14072     (flush _test-error-buffered-file)
14073 #?     # dump _test-error-stream {{{
14074 #?     (write 2 "^")
14075 #?     (write-stream 2 _test-error-stream)
14076 #?     (write 2 "$\n")
14077 #?     (rewind-stream _test-error-stream)
14078 #?     # }}}
14079     # check output
14080     (check-stream-equal _test-output-stream  ""  "F - test-length-with-too-many-outputs: output should be empty")
14081     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt length: too many outputs (1 required)"  "F - test-length-with-too-many-outputs: error message")
14082     # check that stop(1) was called
14083     (check-ints-equal *(edx+4) 2 "F - test-length-with-too-many-outputs: exit status")
14084     # don't restore from ebp
14085     81 0/subop/add %esp 8/imm32
14086     # . epilogue
14087     5d/pop-to-ebp
14088     c3/return
14090 test-convert-function-with-return-register-and-local:
14091     # . prologue
14092     55/push-ebp
14093     89/<- %ebp 4/r32/esp
14094     # setup
14095     (clear-stream _test-input-stream)
14096     (clear-stream $_test-input-buffered-file->buffer)
14097     (clear-stream _test-output-stream)
14098     (clear-stream $_test-output-buffered-file->buffer)
14099     #
14100     (write _test-input-stream "fn foo -> _/eax: int {\n")
14101     (write _test-input-stream "  var y/eax: int <- copy 3\n")
14102     (write _test-input-stream "  var z/ecx: int <- copy 4\n")
14103     (write _test-input-stream "  return y\n")
14104     (write _test-input-stream "}\n")
14105     # convert
14106     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
14107     (flush _test-output-buffered-file)
14108 #?     # dump _test-output-stream {{{
14109 #?     (write 2 "^")
14110 #?     (write-stream 2 _test-output-stream)
14111 #?     (write 2 "$\n")
14112 #?     (rewind-stream _test-output-stream)
14113 #?     # }}}
14114     # check output
14115     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-return-register-and-local/0")
14116     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-return-register-and-local/1")
14117     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-return-register-and-local/2")
14118     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-return-register-and-local/3")
14119     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-return-register-and-local/4")
14120     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-return-register-and-local/5")
14121     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-function-with-return-register-and-local/6")
14122     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-convert-function-with-return-register-and-local/7")
14123     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-return-register-and-local/8")
14124     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-convert-function-with-return-register-and-local/9")
14125     (check-next-stream-line-equal _test-output-stream "    8b/-> %eax 0x00000000/r32" "F - test-convert-function-with-return-register-and-local/10")
14126     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"         "F - test-convert-function-with-return-register-and-local/11")
14127     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 4/imm32"  "F - test-convert-function-with-return-register-and-local/12")
14128     (check-next-stream-line-equal _test-output-stream "    e9/jump $foo:0x00000001:break/disp32"  "F - test-convert-function-with-return-register-and-local/13")
14129     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-return-register-and-local/14")
14130     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-return-register-and-local/15")
14131     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-return-register-and-local/16")
14132     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-return-register-and-local/17")
14133     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-return-register-and-local/18")
14134     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-return-register-and-local/19")
14135     # . epilogue
14136     89/<- %esp 5/r32/ebp
14137     5d/pop-to-ebp
14138     c3/return
14140 test-convert-function-with-return-register-and-local-2:
14141     # . prologue
14142     55/push-ebp
14143     89/<- %ebp 4/r32/esp
14144     # setup
14145     (clear-stream _test-input-stream)
14146     (clear-stream $_test-input-buffered-file->buffer)
14147     (clear-stream _test-output-stream)
14148     (clear-stream $_test-output-buffered-file->buffer)
14149     #
14150     (write _test-input-stream "fn foo -> _/eax: int {\n")
14151     (write _test-input-stream "  var y/eax: int <- copy 3\n")
14152     (write _test-input-stream "  var z/ecx: int <- copy 4\n")
14153     (write _test-input-stream "  return z\n")
14154     (write _test-input-stream "}\n")
14155     # convert
14156     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
14157     (flush _test-output-buffered-file)
14158 #?     # dump _test-output-stream {{{
14159 #?     (write 2 "^")
14160 #?     (write-stream 2 _test-output-stream)
14161 #?     (write 2 "$\n")
14162 #?     (rewind-stream _test-output-stream)
14163 #?     # }}}
14164     # check output
14165     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-return-register-and-local-2/0")
14166     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-return-register-and-local-2/1")
14167     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-return-register-and-local-2/2")
14168     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-return-register-and-local-2/3")
14169     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-return-register-and-local-2/4")
14170     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-return-register-and-local-2/5")
14171     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-function-with-return-register-and-local-2/6")
14172     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-convert-function-with-return-register-and-local-2/7")
14173     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-return-register-and-local-2/8")
14174     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-convert-function-with-return-register-and-local-2/9")
14175     (check-next-stream-line-equal _test-output-stream "    8b/-> %ecx 0x00000000/r32" "F - test-convert-function-with-return-register-and-local-2/10")
14176     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"         "F - test-convert-function-with-return-register-and-local-2/11")
14177     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 4/imm32"  "F - test-convert-function-with-return-register-and-local-2/12")
14178     (check-next-stream-line-equal _test-output-stream "    e9/jump $foo:0x00000001:break/disp32"  "F - test-convert-function-with-return-register-and-local-2/13")
14179     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-return-register-and-local-2/14")
14180     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-return-register-and-local-2/15")
14181     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-return-register-and-local-2/16")
14182     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-return-register-and-local-2/17")
14183     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-return-register-and-local-2/18")
14184     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-return-register-and-local-2/19")
14185     # . epilogue
14186     89/<- %esp 5/r32/ebp
14187     5d/pop-to-ebp
14188     c3/return
14190 test-convert-function-with-return-float-register-and-local:
14191     # . prologue
14192     55/push-ebp
14193     89/<- %ebp 4/r32/esp
14194     # setup
14195     (clear-stream _test-input-stream)
14196     (clear-stream $_test-input-buffered-file->buffer)
14197     (clear-stream _test-output-stream)
14198     (clear-stream $_test-output-buffered-file->buffer)
14199     #
14200     (write _test-input-stream "fn foo -> _/xmm1: float {\n")
14201     (write _test-input-stream "  var y/eax: int <- copy 3\n")
14202     (write _test-input-stream "  var g/xmm0: float <- convert y\n")
14203     (write _test-input-stream "  var h/xmm1: float <- convert y\n")
14204     (write _test-input-stream "  return g\n")
14205     (write _test-input-stream "}\n")
14206     # convert
14207     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
14208     (flush _test-output-buffered-file)
14209 #?     # dump _test-output-stream {{{
14210 #?     (write 2 "^")
14211 #?     (write-stream 2 _test-output-stream)
14212 #?     (write 2 "$\n")
14213 #?     (rewind-stream _test-output-stream)
14214 #?     # }}}
14215     # check output
14216     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-return-float-register-and-local/0")
14217     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-return-float-register-and-local/1")
14218     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-return-float-register-and-local/2")
14219     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-return-float-register-and-local/3")
14220     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-return-float-register-and-local/4")
14221     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-return-float-register-and-local/5")
14222     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-function-with-return-float-register-and-local/6")  # var y
14223     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-convert-function-with-return-float-register-and-local/7")
14224     (check-next-stream-line-equal _test-output-stream "    81 5/subop/subtract %esp 4/imm32"  "F - test-convert-function-with-return-float-register-and-local/8")  # var g
14225     (check-next-stream-line-equal _test-output-stream "    f3 0f 11/<- *esp 0/x32"  "F - test-convert-function-with-return-float-register-and-local/9")
14226     (check-next-stream-line-equal _test-output-stream "    f3 0f 2a/convert-to-float %eax 0x00000000/x32"  "F - test-convert-function-with-return-float-register-and-local/10")
14227     (check-next-stream-line-equal _test-output-stream "    81 5/subop/subtract %esp 4/imm32"  "F - test-convert-function-with-return-float-register-and-local/11")  # var h
14228     (check-next-stream-line-equal _test-output-stream "    f3 0f 11/<- *esp 1/x32"  "F - test-convert-function-with-return-float-register-and-local/12")
14229     (check-next-stream-line-equal _test-output-stream "    f3 0f 2a/convert-to-float %eax 0x00000001/x32"  "F - test-convert-function-with-return-float-register-and-local/13")
14230     (check-next-stream-line-equal _test-output-stream "    f3 0f 10/-> %xmm0 0x00000001/x32"  "F - test-convert-function-with-return-float-register-and-local/14")  # return g
14231     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 4/imm32"  "F - test-convert-floating-point-dereferenced/15")  # reclaim h
14232     (check-next-stream-line-equal _test-output-stream "    f3 0f 10/-> *esp 0/x32"  "F - test-convert-floating-point-dereferenced/16")  # reclaim g
14233     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 4/imm32"  "F - test-convert-floating-point-dereferenced/17")
14234     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"         "F - test-convert-function-with-return-float-register-and-local/18")  # reclaim y
14235     (check-next-stream-line-equal _test-output-stream "    e9/jump $foo:0x00000001:break/disp32"  "F - test-convert-function-with-return-float-register-and-local/19")
14236     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-return-float-register-and-local/20")
14237     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-return-float-register-and-local/21")
14238     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-return-float-register-and-local/22")
14239     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-return-float-register-and-local/23")
14240     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-return-float-register-and-local/24")
14241     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-return-float-register-and-local/25")
14242     # . epilogue
14243     89/<- %esp 5/r32/ebp
14244     5d/pop-to-ebp
14245     c3/return
14247 test-convert-function-with-return-and-local-vars:
14248     # . prologue
14249     55/push-ebp
14250     89/<- %ebp 4/r32/esp
14251     # setup
14252     (clear-stream _test-input-stream)
14253     (clear-stream $_test-input-buffered-file->buffer)
14254     (clear-stream _test-output-stream)
14255     (clear-stream $_test-output-buffered-file->buffer)
14256     #
14257     (write _test-input-stream "fn foo -> _/eax: int {\n")
14258     (write _test-input-stream "  {\n")
14259     (write _test-input-stream "    var x: int\n")
14260     (write _test-input-stream "    {\n")
14261     (write _test-input-stream "      var y: int\n")
14262     (write _test-input-stream "      return y\n")
14263     (write _test-input-stream "      increment x\n")
14264     (write _test-input-stream "    }\n")
14265     (write _test-input-stream "  }\n")
14266     (write _test-input-stream "  return 0\n")
14267     (write _test-input-stream "}\n")
14268     # convert
14269     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
14270     (flush _test-output-buffered-file)
14271 #?     # dump _test-output-stream {{{
14272 #?     (write 2 "^")
14273 #?     (write-stream 2 _test-output-stream)
14274 #?     (write 2 "$\n")
14275 #?     (rewind-stream _test-output-stream)
14276 #?     # }}}
14277     # check output
14278     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-return-and-local-vars/0")
14279     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-return-and-local-vars/1")
14280     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-return-and-local-vars/2")
14281     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-return-and-local-vars/3")
14282     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-return-and-local-vars/4")
14283     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-return-and-local-vars/5")
14284     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-return-and-local-vars/6")
14285     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-return-and-local-vars/7")
14286     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-return-and-local-vars/8")  # var x
14287     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-return-and-local-vars/9")
14288     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-return-and-local-vars/10")
14289     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-return-and-local-vars/11")  # var y
14290     (check-next-stream-line-equal _test-output-stream "        8b/-> *(ebp+0xfffffff8) 0x00000000/r32" "F - test-convert-function-with-return-and-local-vars/12")
14291     (check-next-stream-line-equal _test-output-stream "        81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-return-and-local-vars/13")
14292     (check-next-stream-line-equal _test-output-stream "        81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-return-and-local-vars/14")
14293     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000001:break/disp32"  "F - test-convert-function-with-return-and-local-vars/15")
14294     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-return-and-local-vars/16")
14295     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-return-and-local-vars/17")
14296     (check-next-stream-line-equal _test-output-stream "      81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-return-and-local-vars/18")
14297     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-return-and-local-vars/19")
14298     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-return-and-local-vars/20")
14299     (check-next-stream-line-equal _test-output-stream "    c7 0/subop/copy %eax 0/imm32"  "F - test-convert-function-with-return-and-local-vars/21")
14300     (check-next-stream-line-equal _test-output-stream "    e9/jump $foo:0x00000001:break/disp32"  "F - test-convert-function-with-return-and-local-vars/21")
14301     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-return-and-local-vars/21")
14302     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-return-and-local-vars/22")
14303     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-return-and-local-vars/23")
14304     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-return-and-local-vars/24")
14305     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-return-and-local-vars/25")
14306     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-return-and-local-vars/26")
14307     # . epilogue
14308     89/<- %esp 5/r32/ebp
14309     5d/pop-to-ebp
14310     c3/return
14312 test-copy-object-with-no-inout:
14313     # . prologue
14314     55/push-ebp
14315     89/<- %ebp 4/r32/esp
14316     # setup
14317     (clear-stream _test-input-stream)
14318     (clear-stream $_test-input-buffered-file->buffer)
14319     (clear-stream _test-output-stream)
14320     (clear-stream $_test-output-buffered-file->buffer)
14321     (clear-stream _test-error-stream)
14322     (clear-stream $_test-error-buffered-file->buffer)
14323     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
14324     68/push 0/imm32
14325     68/push 0/imm32
14326     89/<- %edx 4/r32/esp
14327     (tailor-exit-descriptor %edx 0x10)
14328     #
14329     (write _test-input-stream "fn foo {\n")
14330     (write _test-input-stream "  copy-object\n")
14331     (write _test-input-stream "}\n")
14332     # convert
14333     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
14334     # registers except esp clobbered at this point
14335     # restore ed
14336     89/<- %edx 4/r32/esp
14337     (flush _test-output-buffered-file)
14338     (flush _test-error-buffered-file)
14339 #?     # dump _test-error-stream {{{
14340 #?     (write 2 "^")
14341 #?     (write-stream 2 _test-error-stream)
14342 #?     (write 2 "$\n")
14343 #?     (rewind-stream _test-error-stream)
14344 #?     # }}}
14345     # check output
14346     (check-stream-equal _test-output-stream  ""  "F - test-copy-object-with-no-inout: output should be empty")
14347     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'copy-object' must have two inouts"  "F - test-copy-object-with-no-inout: error message")
14348     # check that stop(1) was called
14349     (check-ints-equal *(edx+4) 2 "F - test-copy-object-with-no-inout: exit status")
14350     # don't restore from ebp
14351     81 0/subop/add %esp 8/imm32
14352     # . epilogue
14353     5d/pop-to-ebp
14354     c3/return
14356 test-copy-object-with-no-source:
14357     # . prologue
14358     55/push-ebp
14359     89/<- %ebp 4/r32/esp
14360     # setup
14361     (clear-stream _test-input-stream)
14362     (clear-stream $_test-input-buffered-file->buffer)
14363     (clear-stream _test-output-stream)
14364     (clear-stream $_test-output-buffered-file->buffer)
14365     (clear-stream _test-error-stream)
14366     (clear-stream $_test-error-buffered-file->buffer)
14367     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
14368     68/push 0/imm32
14369     68/push 0/imm32
14370     89/<- %edx 4/r32/esp
14371     (tailor-exit-descriptor %edx 0x10)
14372     #
14373     (write _test-input-stream "fn foo {\n")
14374     (write _test-input-stream "  var x: (addr int)\n")
14375     (write _test-input-stream "  copy-object x\n")
14376     (write _test-input-stream "}\n")
14377     # convert
14378     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
14379     # registers except esp clobbered at this point
14380     # restore ed
14381     89/<- %edx 4/r32/esp
14382     (flush _test-output-buffered-file)
14383     (flush _test-error-buffered-file)
14384 #?     # dump _test-error-stream {{{
14385 #?     (write 2 "^")
14386 #?     (write-stream 2 _test-error-stream)
14387 #?     (write 2 "$\n")
14388 #?     (rewind-stream _test-error-stream)
14389 #?     # }}}
14390     # check output
14391     (check-stream-equal _test-output-stream  ""  "F - test-copy-object-with-no-source: output should be empty")
14392     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'copy-object' must have two inouts"  "F - test-copy-object-with-no-source: error message")
14393     # check that stop(1) was called
14394     (check-ints-equal *(edx+4) 2 "F - test-copy-object-with-no-source: exit status")
14395     # don't restore from ebp
14396     81 0/subop/add %esp 8/imm32
14397     # . epilogue
14398     5d/pop-to-ebp
14399     c3/return
14401 test-copy-object-with-too-many-inouts:
14402     # . prologue
14403     55/push-ebp
14404     89/<- %ebp 4/r32/esp
14405     # setup
14406     (clear-stream _test-input-stream)
14407     (clear-stream $_test-input-buffered-file->buffer)
14408     (clear-stream _test-output-stream)
14409     (clear-stream $_test-output-buffered-file->buffer)
14410     (clear-stream _test-error-stream)
14411     (clear-stream $_test-error-buffered-file->buffer)
14412     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
14413     68/push 0/imm32
14414     68/push 0/imm32
14415     89/<- %edx 4/r32/esp
14416     (tailor-exit-descriptor %edx 0x10)
14417     #
14418     (write _test-input-stream "fn foo {\n")
14419     (write _test-input-stream "  var x: (addr boolean)\n")
14420     (write _test-input-stream "  copy-object x, x, x\n")
14421     (write _test-input-stream "}\n")
14422     # convert
14423     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
14424     # registers except esp clobbered at this point
14425     # restore ed
14426     89/<- %edx 4/r32/esp
14427     (flush _test-output-buffered-file)
14428     (flush _test-error-buffered-file)
14429 #?     # dump _test-error-stream {{{
14430 #?     (write 2 "^")
14431 #?     (write-stream 2 _test-error-stream)
14432 #?     (write 2 "$\n")
14433 #?     (rewind-stream _test-error-stream)
14434 #?     # }}}
14435     # check output
14436     (check-stream-equal _test-output-stream  ""  "F - test-copy-object-with-too-many-inouts: output should be empty")
14437     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'copy-object' must have two inouts"  "F - test-copy-object-with-too-many-inouts: error message")
14438     # check that stop(1) was called
14439     (check-ints-equal *(edx+4) 2 "F - test-copy-object-with-too-many-inouts: exit status")
14440     # don't restore from ebp
14441     81 0/subop/add %esp 8/imm32
14442     # . epilogue
14443     5d/pop-to-ebp
14444     c3/return
14446 test-copy-object-with-output:
14447     # . prologue
14448     55/push-ebp
14449     89/<- %ebp 4/r32/esp
14450     # setup
14451     (clear-stream _test-input-stream)
14452     (clear-stream $_test-input-buffered-file->buffer)
14453     (clear-stream _test-output-stream)
14454     (clear-stream $_test-output-buffered-file->buffer)
14455     (clear-stream _test-error-stream)
14456     (clear-stream $_test-error-buffered-file->buffer)
14457     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
14458     68/push 0/imm32
14459     68/push 0/imm32
14460     89/<- %edx 4/r32/esp
14461     (tailor-exit-descriptor %edx 0x10)
14462     #
14463     (write _test-input-stream "fn foo {\n")
14464     (write _test-input-stream "  var x/eax: (addr boolean) <- copy 0\n")
14465     (write _test-input-stream "  var y/ecx: (addr boolean) <- copy 0\n")
14466     (write _test-input-stream "  x <- copy-object x, y\n")
14467     (write _test-input-stream "}\n")
14468     # convert
14469     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
14470     # registers except esp clobbered at this point
14471     # restore ed
14472     89/<- %edx 4/r32/esp
14473     (flush _test-output-buffered-file)
14474     (flush _test-error-buffered-file)
14475 #?     # dump _test-error-stream {{{
14476 #?     (write 2 "^")
14477 #?     (write-stream 2 _test-error-stream)
14478 #?     (write 2 "$\n")
14479 #?     (rewind-stream _test-error-stream)
14480 #?     # }}}
14481     # check output
14482     (check-stream-equal _test-output-stream  ""  "F - test-copy-object-with-output: output should be empty")
14483     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'copy-object' must not have any outputs"  "F - test-copy-object-with-output: error message")
14484     # check that stop(1) was called
14485     (check-ints-equal *(edx+4) 2 "F - test-copy-object-with-output: exit status")
14486     # don't restore from ebp
14487     81 0/subop/add %esp 8/imm32
14488     # . epilogue
14489     5d/pop-to-ebp
14490     c3/return
14492 test-copy-object-deref-address:
14493     # . prologue
14494     55/push-ebp
14495     89/<- %ebp 4/r32/esp
14496     # setup
14497     (clear-stream _test-input-stream)
14498     (clear-stream $_test-input-buffered-file->buffer)
14499     (clear-stream _test-output-stream)
14500     (clear-stream $_test-output-buffered-file->buffer)
14501     #
14502     (write _test-input-stream "fn foo {\n")
14503     (write _test-input-stream "  var x/eax: (addr int) <- copy 0\n")
14504     (write _test-input-stream "  var y/ecx: (addr addr int) <- copy 0\n")
14505     (write _test-input-stream "  copy-object *y, x\n")
14506     (write _test-input-stream "}\n")
14507     # convert
14508     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
14509     (flush _test-output-buffered-file)
14510     # no errors
14511     # . epilogue
14512     5d/pop-to-ebp
14513     c3/return
14515 test-copy-object-non-addr:
14516     # . prologue
14517     55/push-ebp
14518     89/<- %ebp 4/r32/esp
14519     # setup
14520     (clear-stream _test-input-stream)
14521     (clear-stream $_test-input-buffered-file->buffer)
14522     (clear-stream _test-output-stream)
14523     (clear-stream $_test-output-buffered-file->buffer)
14524     (clear-stream _test-error-stream)
14525     (clear-stream $_test-error-buffered-file->buffer)
14526     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
14527     68/push 0/imm32
14528     68/push 0/imm32
14529     89/<- %edx 4/r32/esp
14530     (tailor-exit-descriptor %edx 0x10)
14531     #
14532     (write _test-input-stream "fn foo {\n")
14533     (write _test-input-stream "  var x: int\n")
14534     (write _test-input-stream "  var y: int\n")
14535     (write _test-input-stream "  copy-object y, x\n")
14536     (write _test-input-stream "}\n")
14537     # convert
14538     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
14539     # registers except esp clobbered at this point
14540     # restore ed
14541     89/<- %edx 4/r32/esp
14542     (flush _test-output-buffered-file)
14543     (flush _test-error-buffered-file)
14544 #?     # dump _test-error-stream {{{
14545 #?     (write 2 "^")
14546 #?     (write-stream 2 _test-error-stream)
14547 #?     (write 2 "$\n")
14548 #?     (rewind-stream _test-error-stream)
14549 #?     # }}}
14550     # check output
14551     (check-stream-equal _test-output-stream  ""  "F - test-copy-object-non-addr: output should be empty")
14552     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt copy-object: two inouts with identical addr types expected"  "F - test-copy-object-non-addr: error message")
14553     # check that stop(1) was called
14554     (check-ints-equal *(edx+4) 2 "F - test-copy-object-non-addr: exit status")
14555     # don't restore from ebp
14556     81 0/subop/add %esp 8/imm32
14557     # . epilogue
14558     5d/pop-to-ebp
14559     c3/return
14561 test-copy-object-non-equal:
14562     # . prologue
14563     55/push-ebp
14564     89/<- %ebp 4/r32/esp
14565     # setup
14566     (clear-stream _test-input-stream)
14567     (clear-stream $_test-input-buffered-file->buffer)
14568     (clear-stream _test-output-stream)
14569     (clear-stream $_test-output-buffered-file->buffer)
14570     (clear-stream _test-error-stream)
14571     (clear-stream $_test-error-buffered-file->buffer)
14572     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
14573     68/push 0/imm32
14574     68/push 0/imm32
14575     89/<- %edx 4/r32/esp
14576     (tailor-exit-descriptor %edx 0x10)
14577     #
14578     (write _test-input-stream "fn foo {\n")
14579     (write _test-input-stream "  var x: (addr int)\n")
14580     (write _test-input-stream "  var y: (addr boolean)\n")
14581     (write _test-input-stream "  copy-object y, x\n")
14582     (write _test-input-stream "}\n")
14583     # convert
14584     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
14585     # registers except esp clobbered at this point
14586     # restore ed
14587     89/<- %edx 4/r32/esp
14588     (flush _test-output-buffered-file)
14589     (flush _test-error-buffered-file)
14590 #?     # dump _test-error-stream {{{
14591 #?     (write 2 "^")
14592 #?     (write-stream 2 _test-error-stream)
14593 #?     (write 2 "$\n")
14594 #?     (rewind-stream _test-error-stream)
14595 #?     # }}}
14596     # check output
14597     (check-stream-equal _test-output-stream  ""  "F - test-copy-object-non-equal: output should be empty")
14598     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt copy-object: two inouts with identical addr types expected"  "F - test-copy-object-non-equal: error message")
14599     # check that stop(1) was called
14600     (check-ints-equal *(edx+4) 2 "F - test-copy-object-non-equal: exit status")
14601     # don't restore from ebp
14602     81 0/subop/add %esp 8/imm32
14603     # . epilogue
14604     5d/pop-to-ebp
14605     c3/return
14607 test-allocate-with-no-inout:
14608     # . prologue
14609     55/push-ebp
14610     89/<- %ebp 4/r32/esp
14611     # setup
14612     (clear-stream _test-input-stream)
14613     (clear-stream $_test-input-buffered-file->buffer)
14614     (clear-stream _test-output-stream)
14615     (clear-stream $_test-output-buffered-file->buffer)
14616     (clear-stream _test-error-stream)
14617     (clear-stream $_test-error-buffered-file->buffer)
14618     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
14619     68/push 0/imm32
14620     68/push 0/imm32
14621     89/<- %edx 4/r32/esp
14622     (tailor-exit-descriptor %edx 0x10)
14623     #
14624     (write _test-input-stream "fn foo {\n")
14625     (write _test-input-stream "  allocate\n")
14626     (write _test-input-stream "}\n")
14627     # convert
14628     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
14629     # registers except esp clobbered at this point
14630     # restore ed
14631     89/<- %edx 4/r32/esp
14632     (flush _test-output-buffered-file)
14633     (flush _test-error-buffered-file)
14634 #?     # dump _test-error-stream {{{
14635 #?     (write 2 "^")
14636 #?     (write-stream 2 _test-error-stream)
14637 #?     (write 2 "$\n")
14638 #?     (rewind-stream _test-error-stream)
14639 #?     # }}}
14640     # check output
14641     (check-stream-equal _test-output-stream  ""  "F - test-allocate-with-no-inout: output should be empty")
14642     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'allocate' must have a single inout"  "F - test-allocate-with-no-inout: error message")
14643     # check that stop(1) was called
14644     (check-ints-equal *(edx+4) 2 "F - test-allocate-with-no-inout: exit status")
14645     # don't restore from ebp
14646     81 0/subop/add %esp 8/imm32
14647     # . epilogue
14648     5d/pop-to-ebp
14649     c3/return
14651 test-allocate-with-too-many-inouts:
14652     # . prologue
14653     55/push-ebp
14654     89/<- %ebp 4/r32/esp
14655     # setup
14656     (clear-stream _test-input-stream)
14657     (clear-stream $_test-input-buffered-file->buffer)
14658     (clear-stream _test-output-stream)
14659     (clear-stream $_test-output-buffered-file->buffer)
14660     (clear-stream _test-error-stream)
14661     (clear-stream $_test-error-buffered-file->buffer)
14662     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
14663     68/push 0/imm32
14664     68/push 0/imm32
14665     89/<- %edx 4/r32/esp
14666     (tailor-exit-descriptor %edx 0x10)
14667     #
14668     (write _test-input-stream "fn foo {\n")
14669     (write _test-input-stream "  var x: (addr handle int)\n")
14670     (write _test-input-stream "  allocate x, 0\n")
14671     (write _test-input-stream "}\n")
14672     # convert
14673     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
14674     # registers except esp clobbered at this point
14675     # restore ed
14676     89/<- %edx 4/r32/esp
14677     (flush _test-output-buffered-file)
14678     (flush _test-error-buffered-file)
14679 #?     # dump _test-error-stream {{{
14680 #?     (write 2 "^")
14681 #?     (write-stream 2 _test-error-stream)
14682 #?     (write 2 "$\n")
14683 #?     (rewind-stream _test-error-stream)
14684 #?     # }}}
14685     # check output
14686     (check-stream-equal _test-output-stream  ""  "F - test-allocate-with-too-many-inouts: output should be empty")
14687     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'allocate' must have a single inout"  "F - test-allocate-with-too-many-inouts: error message")
14688     # check that stop(1) was called
14689     (check-ints-equal *(edx+4) 2 "F - test-allocate-with-too-many-inouts: exit status")
14690     # don't restore from ebp
14691     81 0/subop/add %esp 8/imm32
14692     # . epilogue
14693     5d/pop-to-ebp
14694     c3/return
14696 test-allocate-with-output:
14697     # . prologue
14698     55/push-ebp
14699     89/<- %ebp 4/r32/esp
14700     # setup
14701     (clear-stream _test-input-stream)
14702     (clear-stream $_test-input-buffered-file->buffer)
14703     (clear-stream _test-output-stream)
14704     (clear-stream $_test-output-buffered-file->buffer)
14705     (clear-stream _test-error-stream)
14706     (clear-stream $_test-error-buffered-file->buffer)
14707     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
14708     68/push 0/imm32
14709     68/push 0/imm32
14710     89/<- %edx 4/r32/esp
14711     (tailor-exit-descriptor %edx 0x10)
14712     #
14713     (write _test-input-stream "fn foo {\n")
14714     (write _test-input-stream "  var x/eax: boolean <- copy 0\n")
14715     (write _test-input-stream "  var y/ecx: (addr handle int) <- copy 0\n")
14716     (write _test-input-stream "  x <- allocate y\n")
14717     (write _test-input-stream "}\n")
14718     # convert
14719     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
14720     # registers except esp clobbered at this point
14721     # restore ed
14722     89/<- %edx 4/r32/esp
14723     (flush _test-output-buffered-file)
14724     (flush _test-error-buffered-file)
14725 #?     # dump _test-error-stream {{{
14726 #?     (write 2 "^")
14727 #?     (write-stream 2 _test-error-stream)
14728 #?     (write 2 "$\n")
14729 #?     (rewind-stream _test-error-stream)
14730 #?     # }}}
14731     # check output
14732     (check-stream-equal _test-output-stream  ""  "F - test-allocate-with-output: output should be empty")
14733     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'allocate' must not have any outputs"  "F - test-allocate-with-output: error message")
14734     # check that stop(1) was called
14735     (check-ints-equal *(edx+4) 2 "F - test-allocate-with-output: exit status")
14736     # don't restore from ebp
14737     81 0/subop/add %esp 8/imm32
14738     # . epilogue
14739     5d/pop-to-ebp
14740     c3/return
14742 test-allocate-non-addr:
14743     # . prologue
14744     55/push-ebp
14745     89/<- %ebp 4/r32/esp
14746     # setup
14747     (clear-stream _test-input-stream)
14748     (clear-stream $_test-input-buffered-file->buffer)
14749     (clear-stream _test-output-stream)
14750     (clear-stream $_test-output-buffered-file->buffer)
14751     (clear-stream _test-error-stream)
14752     (clear-stream $_test-error-buffered-file->buffer)
14753     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
14754     68/push 0/imm32
14755     68/push 0/imm32
14756     89/<- %edx 4/r32/esp
14757     (tailor-exit-descriptor %edx 0x10)
14758     #
14759     (write _test-input-stream "fn foo {\n")
14760     (write _test-input-stream "  var y: (handle int)\n")
14761     (write _test-input-stream "  allocate y\n")
14762     (write _test-input-stream "}\n")
14763     # convert
14764     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
14765     # registers except esp clobbered at this point
14766     # restore ed
14767     89/<- %edx 4/r32/esp
14768     (flush _test-output-buffered-file)
14769     (flush _test-error-buffered-file)
14770 #?     # dump _test-error-stream {{{
14771 #?     (write 2 "^")
14772 #?     (write-stream 2 _test-error-stream)
14773 #?     (write 2 "$\n")
14774 #?     (rewind-stream _test-error-stream)
14775 #?     # }}}
14776     # check output
14777     (check-stream-equal _test-output-stream  ""  "F - test-allocate-non-addr: output must be empty")
14778     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt allocate: inout 'y' must have type (addr handle ...)"  "F - test-allocate-non-addr: error message")
14779     # check that stop(1) was called
14780     (check-ints-equal *(edx+4) 2 "F - test-allocate-non-addr: exit status")
14781     # don't restore from ebp
14782     81 0/subop/add %esp 8/imm32
14783     # . epilogue
14784     5d/pop-to-ebp
14785     c3/return
14787 test-allocate-non-addr-handle:
14788     # . prologue
14789     55/push-ebp
14790     89/<- %ebp 4/r32/esp
14791     # setup
14792     (clear-stream _test-input-stream)
14793     (clear-stream $_test-input-buffered-file->buffer)
14794     (clear-stream _test-output-stream)
14795     (clear-stream $_test-output-buffered-file->buffer)
14796     (clear-stream _test-error-stream)
14797     (clear-stream $_test-error-buffered-file->buffer)
14798     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
14799     68/push 0/imm32
14800     68/push 0/imm32
14801     89/<- %edx 4/r32/esp
14802     (tailor-exit-descriptor %edx 0x10)
14803     #
14804     (write _test-input-stream "fn foo {\n")
14805     (write _test-input-stream "  var y/ecx: (addr int) <- copy 0\n")
14806     (write _test-input-stream "  allocate y\n")
14807     (write _test-input-stream "}\n")
14808     # convert
14809     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
14810     # registers except esp clobbered at this point
14811     # restore ed
14812     89/<- %edx 4/r32/esp
14813     (flush _test-output-buffered-file)
14814     (flush _test-error-buffered-file)
14815 #?     # dump _test-error-stream {{{
14816 #?     (write 2 "^")
14817 #?     (write-stream 2 _test-error-stream)
14818 #?     (write 2 "$\n")
14819 #?     (rewind-stream _test-error-stream)
14820 #?     # }}}
14821     # check output
14822     (check-stream-equal _test-output-stream  ""  "F - test-allocate-non-addr-handle: output should be empty")
14823     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt allocate: inout 'y' must have type (addr handle ...)"  "F - test-allocate-non-addr-handle: error message")
14824     # check that stop(1) was called
14825     (check-ints-equal *(edx+4) 2 "F - test-allocate-non-addr-handle: exit status")
14826     # don't restore from ebp
14827     81 0/subop/add %esp 8/imm32
14828     # . epilogue
14829     5d/pop-to-ebp
14830     c3/return
14832 test-allocate-deref-address:
14833     # . prologue
14834     55/push-ebp
14835     89/<- %ebp 4/r32/esp
14836     # setup
14837     (clear-stream _test-input-stream)
14838     (clear-stream $_test-input-buffered-file->buffer)
14839     (clear-stream _test-output-stream)
14840     (clear-stream $_test-output-buffered-file->buffer)
14841     #
14842     (write _test-input-stream "fn foo {\n")
14843     (write _test-input-stream "  var y/ecx: (addr addr handle int) <- copy 0\n")
14844     (write _test-input-stream "  allocate *y\n")
14845     (write _test-input-stream "}\n")
14846     # convert
14847     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
14848     (flush _test-output-buffered-file)
14849     # no errors
14850     # . epilogue
14851     5d/pop-to-ebp
14852     c3/return
14854 test-populate-with-no-inout:
14855     # . prologue
14856     55/push-ebp
14857     89/<- %ebp 4/r32/esp
14858     # setup
14859     (clear-stream _test-input-stream)
14860     (clear-stream $_test-input-buffered-file->buffer)
14861     (clear-stream _test-output-stream)
14862     (clear-stream $_test-output-buffered-file->buffer)
14863     (clear-stream _test-error-stream)
14864     (clear-stream $_test-error-buffered-file->buffer)
14865     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
14866     68/push 0/imm32
14867     68/push 0/imm32
14868     89/<- %edx 4/r32/esp
14869     (tailor-exit-descriptor %edx 0x10)
14870     #
14871     (write _test-input-stream "fn foo {\n")
14872     (write _test-input-stream "  populate\n")
14873     (write _test-input-stream "}\n")
14874     # convert
14875     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
14876     # registers except esp clobbered at this point
14877     # restore ed
14878     89/<- %edx 4/r32/esp
14879     (flush _test-output-buffered-file)
14880     (flush _test-error-buffered-file)
14881 #?     # dump _test-error-stream {{{
14882 #?     (write 2 "^")
14883 #?     (write-stream 2 _test-error-stream)
14884 #?     (write 2 "$\n")
14885 #?     (rewind-stream _test-error-stream)
14886 #?     # }}}
14887     # check output
14888     (check-stream-equal _test-output-stream  ""  "F - test-populate-with-no-inout: output should be empty")
14889     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'populate' must have two inouts"  "F - test-populate-with-no-inout: error message")
14890     # check that stop(1) was called
14891     (check-ints-equal *(edx+4) 2 "F - test-populate-with-no-inout: exit status")
14892     # don't restore from ebp
14893     81 0/subop/add %esp 8/imm32
14894     # . epilogue
14895     5d/pop-to-ebp
14896     c3/return
14898 test-populate-with-too-many-inouts:
14899     # . prologue
14900     55/push-ebp
14901     89/<- %ebp 4/r32/esp
14902     # setup
14903     (clear-stream _test-input-stream)
14904     (clear-stream $_test-input-buffered-file->buffer)
14905     (clear-stream _test-output-stream)
14906     (clear-stream $_test-output-buffered-file->buffer)
14907     (clear-stream _test-error-stream)
14908     (clear-stream $_test-error-buffered-file->buffer)
14909     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
14910     68/push 0/imm32
14911     68/push 0/imm32
14912     89/<- %edx 4/r32/esp
14913     (tailor-exit-descriptor %edx 0x10)
14914     #
14915     (write _test-input-stream "fn foo {\n")
14916     (write _test-input-stream "  var x: (addr handle int)\n")
14917     (write _test-input-stream "  populate x, 3, 0\n")
14918     (write _test-input-stream "}\n")
14919     # convert
14920     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
14921     # registers except esp clobbered at this point
14922     # restore ed
14923     89/<- %edx 4/r32/esp
14924     (flush _test-output-buffered-file)
14925     (flush _test-error-buffered-file)
14926 #?     # dump _test-error-stream {{{
14927 #?     (write 2 "^")
14928 #?     (write-stream 2 _test-error-stream)
14929 #?     (write 2 "$\n")
14930 #?     (rewind-stream _test-error-stream)
14931 #?     # }}}
14932     # check output
14933     (check-stream-equal _test-output-stream  ""  "F - test-populate-with-too-many-inouts: output should be empty")
14934     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'populate' must have two inouts"  "F - test-populate-with-too-many-inouts: error message")
14935     # check that stop(1) was called
14936     (check-ints-equal *(edx+4) 2 "F - test-populate-with-too-many-inouts: exit status")
14937     # don't restore from ebp
14938     81 0/subop/add %esp 8/imm32
14939     # . epilogue
14940     5d/pop-to-ebp
14941     c3/return
14943 test-populate-with-output:
14944     # . prologue
14945     55/push-ebp
14946     89/<- %ebp 4/r32/esp
14947     # setup
14948     (clear-stream _test-input-stream)
14949     (clear-stream $_test-input-buffered-file->buffer)
14950     (clear-stream _test-output-stream)
14951     (clear-stream $_test-output-buffered-file->buffer)
14952     (clear-stream _test-error-stream)
14953     (clear-stream $_test-error-buffered-file->buffer)
14954     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
14955     68/push 0/imm32
14956     68/push 0/imm32
14957     89/<- %edx 4/r32/esp
14958     (tailor-exit-descriptor %edx 0x10)
14959     #
14960     (write _test-input-stream "fn foo {\n")
14961     (write _test-input-stream "  var x/eax: boolean <- copy 0\n")
14962     (write _test-input-stream "  var y/ecx: (addr handle int) <- copy 0\n")
14963     (write _test-input-stream "  x <- populate y\n")
14964     (write _test-input-stream "}\n")
14965     # convert
14966     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
14967     # registers except esp clobbered at this point
14968     # restore ed
14969     89/<- %edx 4/r32/esp
14970     (flush _test-output-buffered-file)
14971     (flush _test-error-buffered-file)
14972 #?     # dump _test-error-stream {{{
14973 #?     (write 2 "^")
14974 #?     (write-stream 2 _test-error-stream)
14975 #?     (write 2 "$\n")
14976 #?     (rewind-stream _test-error-stream)
14977 #?     # }}}
14978     # check output
14979     (check-stream-equal _test-output-stream  ""  "F - test-populate-with-output: output should be empty")
14980     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'populate' must not have any outputs"  "F - test-populate-with-output: error message")
14981     # check that stop(1) was called
14982     (check-ints-equal *(edx+4) 2 "F - test-populate-with-output: exit status")
14983     # don't restore from ebp
14984     81 0/subop/add %esp 8/imm32
14985     # . epilogue
14986     5d/pop-to-ebp
14987     c3/return
14989 test-populate-non-addr:
14990     # . prologue
14991     55/push-ebp
14992     89/<- %ebp 4/r32/esp
14993     # setup
14994     (clear-stream _test-input-stream)
14995     (clear-stream $_test-input-buffered-file->buffer)
14996     (clear-stream _test-output-stream)
14997     (clear-stream $_test-output-buffered-file->buffer)
14998     (clear-stream _test-error-stream)
14999     (clear-stream $_test-error-buffered-file->buffer)
15000     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
15001     68/push 0/imm32
15002     68/push 0/imm32
15003     89/<- %edx 4/r32/esp
15004     (tailor-exit-descriptor %edx 0x10)
15005     #
15006     (write _test-input-stream "fn foo {\n")
15007     (write _test-input-stream "  var y: (handle int)\n")
15008     (write _test-input-stream "  populate y, 3\n")
15009     (write _test-input-stream "}\n")
15010     # convert
15011     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
15012     # registers except esp clobbered at this point
15013     # restore ed
15014     89/<- %edx 4/r32/esp
15015     (flush _test-output-buffered-file)
15016     (flush _test-error-buffered-file)
15017 #?     # dump _test-error-stream {{{
15018 #?     (write 2 "^")
15019 #?     (write-stream 2 _test-error-stream)
15020 #?     (write 2 "$\n")
15021 #?     (rewind-stream _test-error-stream)
15022 #?     # }}}
15023     # check output
15024     (check-stream-equal _test-output-stream  ""  "F - test-populate-non-addr: output must be empty")
15025     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt populate: first inout 'y' must have type (addr handle array ...)"  "F - test-populate-non-addr: error message")
15026     # check that stop(1) was called
15027     (check-ints-equal *(edx+4) 2 "F - test-populate-non-addr: exit status")
15028     # don't restore from ebp
15029     81 0/subop/add %esp 8/imm32
15030     # . epilogue
15031     5d/pop-to-ebp
15032     c3/return
15034 test-populate-non-addr-handle:
15035     # . prologue
15036     55/push-ebp
15037     89/<- %ebp 4/r32/esp
15038     # setup
15039     (clear-stream _test-input-stream)
15040     (clear-stream $_test-input-buffered-file->buffer)
15041     (clear-stream _test-output-stream)
15042     (clear-stream $_test-output-buffered-file->buffer)
15043     (clear-stream _test-error-stream)
15044     (clear-stream $_test-error-buffered-file->buffer)
15045     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
15046     68/push 0/imm32
15047     68/push 0/imm32
15048     89/<- %edx 4/r32/esp
15049     (tailor-exit-descriptor %edx 0x10)
15050     #
15051     (write _test-input-stream "fn foo {\n")
15052     (write _test-input-stream "  var y/ecx: (addr int) <- copy 0\n")
15053     (write _test-input-stream "  populate y, 3\n")
15054     (write _test-input-stream "}\n")
15055     # convert
15056     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
15057     # registers except esp clobbered at this point
15058     # restore ed
15059     89/<- %edx 4/r32/esp
15060     (flush _test-output-buffered-file)
15061     (flush _test-error-buffered-file)
15062 #?     # dump _test-error-stream {{{
15063 #?     (write 2 "^")
15064 #?     (write-stream 2 _test-error-stream)
15065 #?     (write 2 "$\n")
15066 #?     (rewind-stream _test-error-stream)
15067 #?     # }}}
15068     # check output
15069     (check-stream-equal _test-output-stream  ""  "F - test-populate-non-addr-handle: output should be empty")
15070     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt populate: first inout 'y' must have type (addr handle array ...)"  "F - test-populate-non-addr-handle: error message")
15071     # check that stop(1) was called
15072     (check-ints-equal *(edx+4) 2 "F - test-populate-non-addr-handle: exit status")
15073     # don't restore from ebp
15074     81 0/subop/add %esp 8/imm32
15075     # . epilogue
15076     5d/pop-to-ebp
15077     c3/return
15079 test-populate-non-addr-handle-array:
15080     # . prologue
15081     55/push-ebp
15082     89/<- %ebp 4/r32/esp
15083     # setup
15084     (clear-stream _test-input-stream)
15085     (clear-stream $_test-input-buffered-file->buffer)
15086     (clear-stream _test-output-stream)
15087     (clear-stream $_test-output-buffered-file->buffer)
15088     (clear-stream _test-error-stream)
15089     (clear-stream $_test-error-buffered-file->buffer)
15090     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
15091     68/push 0/imm32
15092     68/push 0/imm32
15093     89/<- %edx 4/r32/esp
15094     (tailor-exit-descriptor %edx 0x10)
15095     #
15096     (write _test-input-stream "fn foo {\n")
15097     (write _test-input-stream "  var y/ecx: (addr handle int) <- copy 0\n")
15098     (write _test-input-stream "  populate y, 3\n")
15099     (write _test-input-stream "}\n")
15100     # convert
15101     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
15102     # registers except esp clobbered at this point
15103     # restore ed
15104     89/<- %edx 4/r32/esp
15105     (flush _test-output-buffered-file)
15106     (flush _test-error-buffered-file)
15107 #?     # dump _test-error-stream {{{
15108 #?     (write 2 "^")
15109 #?     (write-stream 2 _test-error-stream)
15110 #?     (write 2 "$\n")
15111 #?     (rewind-stream _test-error-stream)
15112 #?     # }}}
15113     # check output
15114     (check-stream-equal _test-output-stream  ""  "F - test-populate-non-addr-handle-array: output should be empty")
15115     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt populate: first inout 'y' must have type (addr handle array ...)"  "F - test-populate-non-addr-handle-array: error message")
15116     # check that stop(1) was called
15117     (check-ints-equal *(edx+4) 2 "F - test-populate-non-addr-handle-array: exit status")
15118     # don't restore from ebp
15119     81 0/subop/add %esp 8/imm32
15120     # . epilogue
15121     5d/pop-to-ebp
15122     c3/return
15124 test-populate-deref-address:
15125     # . prologue
15126     55/push-ebp
15127     89/<- %ebp 4/r32/esp
15128     # setup
15129     (clear-stream _test-input-stream)
15130     (clear-stream $_test-input-buffered-file->buffer)
15131     (clear-stream _test-output-stream)
15132     (clear-stream $_test-output-buffered-file->buffer)
15133     #
15134     (write _test-input-stream "fn foo {\n")
15135     (write _test-input-stream "  var y/ecx: (addr addr handle array int) <- copy 0\n")
15136     (write _test-input-stream "  populate *y, 3\n")
15137     (write _test-input-stream "}\n")
15138     # convert
15139     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
15140     (flush _test-output-buffered-file)
15141     # no errors
15142     # . epilogue
15143     5d/pop-to-ebp
15144     c3/return
15146 test-populate-stream-with-no-inout:
15147     # . prologue
15148     55/push-ebp
15149     89/<- %ebp 4/r32/esp
15150     # setup
15151     (clear-stream _test-input-stream)
15152     (clear-stream $_test-input-buffered-file->buffer)
15153     (clear-stream _test-output-stream)
15154     (clear-stream $_test-output-buffered-file->buffer)
15155     (clear-stream _test-error-stream)
15156     (clear-stream $_test-error-buffered-file->buffer)
15157     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
15158     68/push 0/imm32
15159     68/push 0/imm32
15160     89/<- %edx 4/r32/esp
15161     (tailor-exit-descriptor %edx 0x10)
15162     #
15163     (write _test-input-stream "fn foo {\n")
15164     (write _test-input-stream "  populate-stream\n")
15165     (write _test-input-stream "}\n")
15166     # convert
15167     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
15168     # registers except esp clobbered at this point
15169     # restore ed
15170     89/<- %edx 4/r32/esp
15171     (flush _test-output-buffered-file)
15172     (flush _test-error-buffered-file)
15173 #?     # dump _test-error-stream {{{
15174 #?     (write 2 "^")
15175 #?     (write-stream 2 _test-error-stream)
15176 #?     (write 2 "$\n")
15177 #?     (rewind-stream _test-error-stream)
15178 #?     # }}}
15179     # check output
15180     (check-stream-equal _test-output-stream  ""  "F - test-populate-stream-with-no-inout: output should be empty")
15181     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'populate-stream' must have two inouts"  "F - test-populate-stream-with-no-inout: error message")
15182     # check that stop(1) was called
15183     (check-ints-equal *(edx+4) 2 "F - test-populate-stream-with-no-inout: exit status")
15184     # don't restore from ebp
15185     81 0/subop/add %esp 8/imm32
15186     # . epilogue
15187     5d/pop-to-ebp
15188     c3/return
15190 test-populate-stream-with-too-many-inouts:
15191     # . prologue
15192     55/push-ebp
15193     89/<- %ebp 4/r32/esp
15194     # setup
15195     (clear-stream _test-input-stream)
15196     (clear-stream $_test-input-buffered-file->buffer)
15197     (clear-stream _test-output-stream)
15198     (clear-stream $_test-output-buffered-file->buffer)
15199     (clear-stream _test-error-stream)
15200     (clear-stream $_test-error-buffered-file->buffer)
15201     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
15202     68/push 0/imm32
15203     68/push 0/imm32
15204     89/<- %edx 4/r32/esp
15205     (tailor-exit-descriptor %edx 0x10)
15206     #
15207     (write _test-input-stream "fn foo {\n")
15208     (write _test-input-stream "  var x: (addr handle int)\n")
15209     (write _test-input-stream "  populate-stream x, 3, 0\n")
15210     (write _test-input-stream "}\n")
15211     # convert
15212     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
15213     # registers except esp clobbered at this point
15214     # restore ed
15215     89/<- %edx 4/r32/esp
15216     (flush _test-output-buffered-file)
15217     (flush _test-error-buffered-file)
15218 #?     # dump _test-error-stream {{{
15219 #?     (write 2 "^")
15220 #?     (write-stream 2 _test-error-stream)
15221 #?     (write 2 "$\n")
15222 #?     (rewind-stream _test-error-stream)
15223 #?     # }}}
15224     # check output
15225     (check-stream-equal _test-output-stream  ""  "F - test-populate-stream-with-too-many-inouts: output should be empty")
15226     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'populate-stream' must have two inouts"  "F - test-populate-stream-with-too-many-inouts: error message")
15227     # check that stop(1) was called
15228     (check-ints-equal *(edx+4) 2 "F - test-populate-stream-with-too-many-inouts: exit status")
15229     # don't restore from ebp
15230     81 0/subop/add %esp 8/imm32
15231     # . epilogue
15232     5d/pop-to-ebp
15233     c3/return
15235 test-populate-stream-with-output:
15236     # . prologue
15237     55/push-ebp
15238     89/<- %ebp 4/r32/esp
15239     # setup
15240     (clear-stream _test-input-stream)
15241     (clear-stream $_test-input-buffered-file->buffer)
15242     (clear-stream _test-output-stream)
15243     (clear-stream $_test-output-buffered-file->buffer)
15244     (clear-stream _test-error-stream)
15245     (clear-stream $_test-error-buffered-file->buffer)
15246     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
15247     68/push 0/imm32
15248     68/push 0/imm32
15249     89/<- %edx 4/r32/esp
15250     (tailor-exit-descriptor %edx 0x10)
15251     #
15252     (write _test-input-stream "fn foo {\n")
15253     (write _test-input-stream "  var x/eax: boolean <- copy 0\n")
15254     (write _test-input-stream "  var y/ecx: (addr handle int) <- copy 0\n")
15255     (write _test-input-stream "  x <- populate-stream y\n")
15256     (write _test-input-stream "}\n")
15257     # convert
15258     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
15259     # registers except esp clobbered at this point
15260     # restore ed
15261     89/<- %edx 4/r32/esp
15262     (flush _test-output-buffered-file)
15263     (flush _test-error-buffered-file)
15264 #?     # dump _test-error-stream {{{
15265 #?     (write 2 "^")
15266 #?     (write-stream 2 _test-error-stream)
15267 #?     (write 2 "$\n")
15268 #?     (rewind-stream _test-error-stream)
15269 #?     # }}}
15270     # check output
15271     (check-stream-equal _test-output-stream  ""  "F - test-populate-stream-with-output: output should be empty")
15272     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'populate-stream' must not have any outputs"  "F - test-populate-stream-with-output: error message")
15273     # check that stop(1) was called
15274     (check-ints-equal *(edx+4) 2 "F - test-populate-stream-with-output: exit status")
15275     # don't restore from ebp
15276     81 0/subop/add %esp 8/imm32
15277     # . epilogue
15278     5d/pop-to-ebp
15279     c3/return
15281 test-populate-stream-non-addr:
15282     # . prologue
15283     55/push-ebp
15284     89/<- %ebp 4/r32/esp
15285     # setup
15286     (clear-stream _test-input-stream)
15287     (clear-stream $_test-input-buffered-file->buffer)
15288     (clear-stream _test-output-stream)
15289     (clear-stream $_test-output-buffered-file->buffer)
15290     (clear-stream _test-error-stream)
15291     (clear-stream $_test-error-buffered-file->buffer)
15292     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
15293     68/push 0/imm32
15294     68/push 0/imm32
15295     89/<- %edx 4/r32/esp
15296     (tailor-exit-descriptor %edx 0x10)
15297     #
15298     (write _test-input-stream "fn foo {\n")
15299     (write _test-input-stream "  var y: (handle int)\n")
15300     (write _test-input-stream "  populate-stream y, 3\n")
15301     (write _test-input-stream "}\n")
15302     # convert
15303     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
15304     # registers except esp clobbered at this point
15305     # restore ed
15306     89/<- %edx 4/r32/esp
15307     (flush _test-output-buffered-file)
15308     (flush _test-error-buffered-file)
15309 #?     # dump _test-error-stream {{{
15310 #?     (write 2 "^")
15311 #?     (write-stream 2 _test-error-stream)
15312 #?     (write 2 "$\n")
15313 #?     (rewind-stream _test-error-stream)
15314 #?     # }}}
15315     # check output
15316     (check-stream-equal _test-output-stream  ""  "F - test-populate-stream-non-addr: output must be empty")
15317     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt populate-stream: first inout 'y' must have type (addr handle stream ...)"  "F - test-populate-stream-non-addr: error message")
15318     # check that stop(1) was called
15319     (check-ints-equal *(edx+4) 2 "F - test-populate-stream-non-addr: exit status")
15320     # don't restore from ebp
15321     81 0/subop/add %esp 8/imm32
15322     # . epilogue
15323     5d/pop-to-ebp
15324     c3/return
15326 test-populate-stream-non-addr-handle:
15327     # . prologue
15328     55/push-ebp
15329     89/<- %ebp 4/r32/esp
15330     # setup
15331     (clear-stream _test-input-stream)
15332     (clear-stream $_test-input-buffered-file->buffer)
15333     (clear-stream _test-output-stream)
15334     (clear-stream $_test-output-buffered-file->buffer)
15335     (clear-stream _test-error-stream)
15336     (clear-stream $_test-error-buffered-file->buffer)
15337     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
15338     68/push 0/imm32
15339     68/push 0/imm32
15340     89/<- %edx 4/r32/esp
15341     (tailor-exit-descriptor %edx 0x10)
15342     #
15343     (write _test-input-stream "fn foo {\n")
15344     (write _test-input-stream "  var y/ecx: (addr int) <- copy 0\n")
15345     (write _test-input-stream "  populate-stream y, 3\n")
15346     (write _test-input-stream "}\n")
15347     # convert
15348     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
15349     # registers except esp clobbered at this point
15350     # restore ed
15351     89/<- %edx 4/r32/esp
15352     (flush _test-output-buffered-file)
15353     (flush _test-error-buffered-file)
15354 #?     # dump _test-error-stream {{{
15355 #?     (write 2 "^")
15356 #?     (write-stream 2 _test-error-stream)
15357 #?     (write 2 "$\n")
15358 #?     (rewind-stream _test-error-stream)
15359 #?     # }}}
15360     # check output
15361     (check-stream-equal _test-output-stream  ""  "F - test-populate-stream-non-addr-handle: output should be empty")
15362     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt populate-stream: first inout 'y' must have type (addr handle stream ...)"  "F - test-populate-stream-non-addr-handle: error message")
15363     # check that stop(1) was called
15364     (check-ints-equal *(edx+4) 2 "F - test-populate-stream-non-addr-handle: exit status")
15365     # don't restore from ebp
15366     81 0/subop/add %esp 8/imm32
15367     # . epilogue
15368     5d/pop-to-ebp
15369     c3/return
15371 test-populate-stream-non-addr-handle-stream:
15372     # . prologue
15373     55/push-ebp
15374     89/<- %ebp 4/r32/esp
15375     # setup
15376     (clear-stream _test-input-stream)
15377     (clear-stream $_test-input-buffered-file->buffer)
15378     (clear-stream _test-output-stream)
15379     (clear-stream $_test-output-buffered-file->buffer)
15380     (clear-stream _test-error-stream)
15381     (clear-stream $_test-error-buffered-file->buffer)
15382     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
15383     68/push 0/imm32
15384     68/push 0/imm32
15385     89/<- %edx 4/r32/esp
15386     (tailor-exit-descriptor %edx 0x10)
15387     #
15388     (write _test-input-stream "fn foo {\n")
15389     (write _test-input-stream "  var y/ecx: (addr handle int) <- copy 0\n")
15390     (write _test-input-stream "  populate-stream y, 3\n")
15391     (write _test-input-stream "}\n")
15392     # convert
15393     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
15394     # registers except esp clobbered at this point
15395     # restore ed
15396     89/<- %edx 4/r32/esp
15397     (flush _test-output-buffered-file)
15398     (flush _test-error-buffered-file)
15399 #?     # dump _test-error-stream {{{
15400 #?     (write 2 "^")
15401 #?     (write-stream 2 _test-error-stream)
15402 #?     (write 2 "$\n")
15403 #?     (rewind-stream _test-error-stream)
15404 #?     # }}}
15405     # check output
15406     (check-stream-equal _test-output-stream  ""  "F - test-populate-stream-non-addr-handle-stream: output should be empty")
15407     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt populate-stream: first inout 'y' must have type (addr handle stream ...)"  "F - test-populate-stream-non-addr-handle-stream: error message")
15408     # check that stop(1) was called
15409     (check-ints-equal *(edx+4) 2 "F - test-populate-stream-non-addr-handle-stream: exit status")
15410     # don't restore from ebp
15411     81 0/subop/add %esp 8/imm32
15412     # . epilogue
15413     5d/pop-to-ebp
15414     c3/return
15416 test-populate-stream-deref-address:
15417     # . prologue
15418     55/push-ebp
15419     89/<- %ebp 4/r32/esp
15420     # setup
15421     (clear-stream _test-input-stream)
15422     (clear-stream $_test-input-buffered-file->buffer)
15423     (clear-stream _test-output-stream)
15424     (clear-stream $_test-output-buffered-file->buffer)
15425     #
15426     (write _test-input-stream "fn foo {\n")
15427     (write _test-input-stream "  var y/ecx: (addr addr handle stream int) <- copy 0\n")
15428     (write _test-input-stream "  populate-stream *y, 3\n")
15429     (write _test-input-stream "}\n")
15430     # convert
15431     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
15432     (flush _test-output-buffered-file)
15433     # no errors
15434     # . epilogue
15435     5d/pop-to-ebp
15436     c3/return
15438 test-convert-with-no-inout:
15439     # . prologue
15440     55/push-ebp
15441     89/<- %ebp 4/r32/esp
15442     # setup
15443     (clear-stream _test-input-stream)
15444     (clear-stream $_test-input-buffered-file->buffer)
15445     (clear-stream _test-output-stream)
15446     (clear-stream $_test-output-buffered-file->buffer)
15447     (clear-stream _test-error-stream)
15448     (clear-stream $_test-error-buffered-file->buffer)
15449     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
15450     68/push 0/imm32
15451     68/push 0/imm32
15452     89/<- %edx 4/r32/esp
15453     (tailor-exit-descriptor %edx 0x10)
15454     #
15455     (write _test-input-stream "fn foo {\n")
15456     (write _test-input-stream "  var x/eax: int <- convert\n")
15457     (write _test-input-stream "}\n")
15458     # convert
15459     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
15460     # registers except esp clobbered at this point
15461     # restore ed
15462     89/<- %edx 4/r32/esp
15463     (flush _test-output-buffered-file)
15464     (flush _test-error-buffered-file)
15465 #?     # dump _test-error-stream {{{
15466 #?     (write 2 "^")
15467 #?     (write-stream 2 _test-error-stream)
15468 #?     (write 2 "$\n")
15469 #?     (rewind-stream _test-error-stream)
15470 #?     # }}}
15471     # check output
15472     (check-stream-equal _test-output-stream  ""  "F - test-convert-with-no-inout: output should be empty")
15473     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'convert' expects an inout"  "F - test-convert-with-no-inout: error message")
15474     # check that stop(1) was called
15475     (check-ints-equal *(edx+4) 2 "F - test-convert-with-no-inout: exit status")
15476     # don't restore from ebp
15477     81 0/subop/add %esp 8/imm32
15478     # . epilogue
15479     5d/pop-to-ebp
15480     c3/return
15482 test-convert-with-multiple-inouts:
15483     # . prologue
15484     55/push-ebp
15485     89/<- %ebp 4/r32/esp
15486     # setup
15487     (clear-stream _test-input-stream)
15488     (clear-stream $_test-input-buffered-file->buffer)
15489     (clear-stream _test-output-stream)
15490     (clear-stream $_test-output-buffered-file->buffer)
15491     (clear-stream _test-error-stream)
15492     (clear-stream $_test-error-buffered-file->buffer)
15493     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
15494     68/push 0/imm32
15495     68/push 0/imm32
15496     89/<- %edx 4/r32/esp
15497     (tailor-exit-descriptor %edx 0x10)
15498     #
15499     (write _test-input-stream "fn foo {\n")
15500     (write _test-input-stream "  var x/eax: int <- convert 0, 0\n")
15501     (write _test-input-stream "}\n")
15502     # convert
15503     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
15504     # registers except esp clobbered at this point
15505     # restore ed
15506     89/<- %edx 4/r32/esp
15507     (flush _test-output-buffered-file)
15508     (flush _test-error-buffered-file)
15509 #?     # dump _test-error-stream {{{
15510 #?     (write 2 "^")
15511 #?     (write-stream 2 _test-error-stream)
15512 #?     (write 2 "$\n")
15513 #?     (rewind-stream _test-error-stream)
15514 #?     # }}}
15515     # check output
15516     (check-stream-equal _test-output-stream  ""  "F - test-convert-with-multiple-inouts: output should be empty")
15517     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'convert' must have just one inout"  "F - test-convert-with-multiple-inouts: error message")
15518     # check that stop(1) was called
15519     (check-ints-equal *(edx+4) 2 "F - test-convert-with-multiple-inouts: exit status")
15520     # don't restore from ebp
15521     81 0/subop/add %esp 8/imm32
15522     # . epilogue
15523     5d/pop-to-ebp
15524     c3/return
15526 test-convert-with-no-output:
15527     # . prologue
15528     55/push-ebp
15529     89/<- %ebp 4/r32/esp
15530     # setup
15531     (clear-stream _test-input-stream)
15532     (clear-stream $_test-input-buffered-file->buffer)
15533     (clear-stream _test-output-stream)
15534     (clear-stream $_test-output-buffered-file->buffer)
15535     (clear-stream _test-error-stream)
15536     (clear-stream $_test-error-buffered-file->buffer)
15537     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
15538     68/push 0/imm32
15539     68/push 0/imm32
15540     89/<- %edx 4/r32/esp
15541     (tailor-exit-descriptor %edx 0x10)
15542     #
15543     (write _test-input-stream "fn foo {\n")
15544     (write _test-input-stream "  convert 0\n")
15545     (write _test-input-stream "}\n")
15546     # convert
15547     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
15548     # registers except esp clobbered at this point
15549     # restore ed
15550     89/<- %edx 4/r32/esp
15551     (flush _test-output-buffered-file)
15552     (flush _test-error-buffered-file)
15553 #?     # dump _test-error-stream {{{
15554 #?     (write 2 "^")
15555 #?     (write-stream 2 _test-error-stream)
15556 #?     (write 2 "$\n")
15557 #?     (rewind-stream _test-error-stream)
15558 #?     # }}}
15559     # check output
15560     (check-stream-equal _test-output-stream  ""  "F - test-convert-with-no-output: output should be empty")
15561     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'convert' expects an output"  "F - test-convert-with-no-output: error message")
15562     # check that stop(1) was called
15563     (check-ints-equal *(edx+4) 2 "F - test-convert-with-no-output: exit status")
15564     # don't restore from ebp
15565     81 0/subop/add %esp 8/imm32
15566     # . epilogue
15567     5d/pop-to-ebp
15568     c3/return
15570 test-convert-with-multiple-outputs:
15571     # . prologue
15572     55/push-ebp
15573     89/<- %ebp 4/r32/esp
15574     # setup
15575     (clear-stream _test-input-stream)
15576     (clear-stream $_test-input-buffered-file->buffer)
15577     (clear-stream _test-output-stream)
15578     (clear-stream $_test-output-buffered-file->buffer)
15579     (clear-stream _test-error-stream)
15580     (clear-stream $_test-error-buffered-file->buffer)
15581     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
15582     68/push 0/imm32
15583     68/push 0/imm32
15584     89/<- %edx 4/r32/esp
15585     (tailor-exit-descriptor %edx 0x10)
15586     #
15587     (write _test-input-stream "fn foo {\n")
15588     (write _test-input-stream "  var x/eax: int <- copy 0\n")
15589     (write _test-input-stream "  var y/ecx: int <- copy 0\n")
15590     (write _test-input-stream "  x, y <- convert 0\n")
15591     (write _test-input-stream "}\n")
15592     # convert
15593     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
15594     # registers except esp clobbered at this point
15595     # restore ed
15596     89/<- %edx 4/r32/esp
15597     (flush _test-output-buffered-file)
15598     (flush _test-error-buffered-file)
15599 #?     # dump _test-error-stream {{{
15600 #?     (write 2 "^")
15601 #?     (write-stream 2 _test-error-stream)
15602 #?     (write 2 "$\n")
15603 #?     (rewind-stream _test-error-stream)
15604 #?     # }}}
15605     # check output
15606     (check-stream-equal _test-output-stream  ""  "F - test-convert-with-multiple-outputs: output should be empty")
15607     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt 'convert' must have just one output"  "F - test-convert-with-multiple-outputs: error message")
15608     # check that stop(1) was called
15609     (check-ints-equal *(edx+4) 2 "F - test-convert-with-multiple-outputs: exit status")
15610     # don't restore from ebp
15611     81 0/subop/add %esp 8/imm32
15612     # . epilogue
15613     5d/pop-to-ebp
15614     c3/return
15616 test-convert-deref-address:
15617     # . prologue
15618     55/push-ebp
15619     89/<- %ebp 4/r32/esp
15620     # setup
15621     (clear-stream _test-input-stream)
15622     (clear-stream $_test-input-buffered-file->buffer)
15623     (clear-stream _test-output-stream)
15624     (clear-stream $_test-output-buffered-file->buffer)
15625     #
15626     (write _test-input-stream "fn foo {\n")
15627     (write _test-input-stream "  var x/eax: (addr int) <- copy 0\n")
15628     (write _test-input-stream "  var y/xmm4: float <- convert *x\n")
15629     (write _test-input-stream "}\n")
15630     # convert
15631     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
15632     (flush _test-output-buffered-file)
15633     # no errors
15634     # . epilogue
15635     5d/pop-to-ebp
15636     c3/return
15638 test-convert-to-non-register:
15639     # . prologue
15640     55/push-ebp
15641     89/<- %ebp 4/r32/esp
15642     # setup
15643     (clear-stream _test-input-stream)
15644     (clear-stream $_test-input-buffered-file->buffer)
15645     (clear-stream _test-output-stream)
15646     (clear-stream $_test-output-buffered-file->buffer)
15647     (clear-stream _test-error-stream)
15648     (clear-stream $_test-error-buffered-file->buffer)
15649     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
15650     68/push 0/imm32
15651     68/push 0/imm32
15652     89/<- %edx 4/r32/esp
15653     (tailor-exit-descriptor %edx 0x10)
15654     #
15655     (write _test-input-stream "fn foo {\n")
15656     (write _test-input-stream "  var x: float\n")
15657     (write _test-input-stream "  var y: int\n")
15658     (write _test-input-stream "  x <- convert y\n")
15659     (write _test-input-stream "}\n")
15660     # convert
15661     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
15662     # registers except esp clobbered at this point
15663     # restore ed
15664     89/<- %edx 4/r32/esp
15665     (flush _test-output-buffered-file)
15666     (flush _test-error-buffered-file)
15667 #?     # dump _test-error-stream {{{
15668 #?     (write 2 "^")
15669 #?     (write-stream 2 _test-error-stream)
15670 #?     (write 2 "$\n")
15671 #?     (rewind-stream _test-error-stream)
15672 #?     # }}}
15673     # check output
15674     (check-stream-equal _test-output-stream  ""  "F - test-convert-to-non-register: output should be empty")
15675     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt convert: output 'x' not in a register"  "F - test-convert-to-non-register: error message")
15676     # check that stop(1) was called
15677     (check-ints-equal *(edx+4) 2 "F - test-convert-to-non-register: exit status")
15678     # don't restore from ebp
15679     81 0/subop/add %esp 8/imm32
15680     # . epilogue
15681     5d/pop-to-ebp
15682     c3/return
15684 test-convert-invalid-inout-type:
15685     # . prologue
15686     55/push-ebp
15687     89/<- %ebp 4/r32/esp
15688     # setup
15689     (clear-stream _test-input-stream)
15690     (clear-stream $_test-input-buffered-file->buffer)
15691     (clear-stream _test-output-stream)
15692     (clear-stream $_test-output-buffered-file->buffer)
15693     (clear-stream _test-error-stream)
15694     (clear-stream $_test-error-buffered-file->buffer)
15695     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
15696     68/push 0/imm32
15697     68/push 0/imm32
15698     89/<- %edx 4/r32/esp
15699     (tailor-exit-descriptor %edx 0x10)
15700     #
15701     (write _test-input-stream "fn foo {\n")
15702     (write _test-input-stream "  var x: boolean\n")
15703     (write _test-input-stream "  var y/xmm1: float <- convert x\n")
15704     (write _test-input-stream "}\n")
15705     # convert
15706     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
15707     # registers except esp clobbered at this point
15708     # restore ed
15709     89/<- %edx 4/r32/esp
15710     (flush _test-output-buffered-file)
15711     (flush _test-error-buffered-file)
15712 #?     # dump _test-error-stream {{{
15713 #?     (write 2 "^")
15714 #?     (write-stream 2 _test-error-stream)
15715 #?     (write 2 "$\n")
15716 #?     (rewind-stream _test-error-stream)
15717 #?     # }}}
15718     # check output
15719     (check-stream-equal _test-output-stream  ""  "F - test-convert-invalid-inout-type: output should be empty")
15720     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt convert: inout 'x' must be an int or float"  "F - test-convert-invalid-inout-type: error message")
15721     # check that stop(1) was called
15722     (check-ints-equal *(edx+4) 2 "F - test-convert-invalid-inout-type: exit status")
15723     # don't restore from ebp
15724     81 0/subop/add %esp 8/imm32
15725     # . epilogue
15726     5d/pop-to-ebp
15727     c3/return
15729 test-convert-invalid-output-type:
15730     # . prologue
15731     55/push-ebp
15732     89/<- %ebp 4/r32/esp
15733     # setup
15734     (clear-stream _test-input-stream)
15735     (clear-stream $_test-input-buffered-file->buffer)
15736     (clear-stream _test-output-stream)
15737     (clear-stream $_test-output-buffered-file->buffer)
15738     (clear-stream _test-error-stream)
15739     (clear-stream $_test-error-buffered-file->buffer)
15740     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
15741     68/push 0/imm32
15742     68/push 0/imm32
15743     89/<- %edx 4/r32/esp
15744     (tailor-exit-descriptor %edx 0x10)
15745     #
15746     (write _test-input-stream "fn foo {\n")
15747     (write _test-input-stream "  var x: float\n")
15748     (write _test-input-stream "  var y/eax: boolean <- convert x\n")
15749     (write _test-input-stream "}\n")
15750     # convert
15751     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
15752     # registers except esp clobbered at this point
15753     # restore ed
15754     89/<- %edx 4/r32/esp
15755     (flush _test-output-buffered-file)
15756     (flush _test-error-buffered-file)
15757 #?     # dump _test-error-stream {{{
15758 #?     (write 2 "^")
15759 #?     (write-stream 2 _test-error-stream)
15760 #?     (write 2 "$\n")
15761 #?     (rewind-stream _test-error-stream)
15762 #?     # }}}
15763     # check output
15764     (check-stream-equal _test-output-stream  ""  "F - test-convert-invalid-output-type: output should be empty")
15765     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt convert: output 'y' must be an int or float"  "F - test-convert-invalid-output-type: error message")
15766     # check that stop(1) was called
15767     (check-ints-equal *(edx+4) 2 "F - test-convert-invalid-output-type: exit status")
15768     # don't restore from ebp
15769     81 0/subop/add %esp 8/imm32
15770     # . epilogue
15771     5d/pop-to-ebp
15772     c3/return
15774 test-convert-int-to-int:
15775     # . prologue
15776     55/push-ebp
15777     89/<- %ebp 4/r32/esp
15778     # setup
15779     (clear-stream _test-input-stream)
15780     (clear-stream $_test-input-buffered-file->buffer)
15781     (clear-stream _test-output-stream)
15782     (clear-stream $_test-output-buffered-file->buffer)
15783     (clear-stream _test-error-stream)
15784     (clear-stream $_test-error-buffered-file->buffer)
15785     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
15786     68/push 0/imm32
15787     68/push 0/imm32
15788     89/<- %edx 4/r32/esp
15789     (tailor-exit-descriptor %edx 0x10)
15790     #
15791     (write _test-input-stream "fn foo {\n")
15792     (write _test-input-stream "  var x: int\n")
15793     (write _test-input-stream "  var y/eax: int <- convert x\n")
15794     (write _test-input-stream "}\n")
15795     # convert
15796     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
15797     # registers except esp clobbered at this point
15798     # restore ed
15799     89/<- %edx 4/r32/esp
15800     (flush _test-output-buffered-file)
15801     (flush _test-error-buffered-file)
15802 #?     # dump _test-error-stream {{{
15803 #?     (write 2 "^")
15804 #?     (write-stream 2 _test-error-stream)
15805 #?     (write 2 "$\n")
15806 #?     (rewind-stream _test-error-stream)
15807 #?     # }}}
15808     # check output
15809     (check-stream-equal _test-output-stream  ""  "F - test-convert-int-to-int: output should be empty")
15810     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt convert: no need to convert int to int"  "F - test-convert-int-to-int: error message")
15811     # check that stop(1) was called
15812     (check-ints-equal *(edx+4) 2 "F - test-convert-int-to-int: exit status")
15813     # don't restore from ebp
15814     81 0/subop/add %esp 8/imm32
15815     # . epilogue
15816     5d/pop-to-ebp
15817     c3/return
15819 test-convert-float-to-float:
15820     # . prologue
15821     55/push-ebp
15822     89/<- %ebp 4/r32/esp
15823     # setup
15824     (clear-stream _test-input-stream)
15825     (clear-stream $_test-input-buffered-file->buffer)
15826     (clear-stream _test-output-stream)
15827     (clear-stream $_test-output-buffered-file->buffer)
15828     (clear-stream _test-error-stream)
15829     (clear-stream $_test-error-buffered-file->buffer)
15830     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
15831     68/push 0/imm32
15832     68/push 0/imm32
15833     89/<- %edx 4/r32/esp
15834     (tailor-exit-descriptor %edx 0x10)
15835     #
15836     (write _test-input-stream "fn foo {\n")
15837     (write _test-input-stream "  var x: float\n")
15838     (write _test-input-stream "  var y/xmm6: float <- convert x\n")
15839     (write _test-input-stream "}\n")
15840     # convert
15841     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
15842     # registers except esp clobbered at this point
15843     # restore ed
15844     89/<- %edx 4/r32/esp
15845     (flush _test-output-buffered-file)
15846     (flush _test-error-buffered-file)
15847 #?     # dump _test-error-stream {{{
15848 #?     (write 2 "^")
15849 #?     (write-stream 2 _test-error-stream)
15850 #?     (write 2 "$\n")
15851 #?     (rewind-stream _test-error-stream)
15852 #?     # }}}
15853     # check output
15854     (check-stream-equal _test-output-stream  ""  "F - test-convert-float-to-float: output should be empty")
15855     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt convert: no need to convert float to float"  "F - test-convert-float-to-float: error message")
15856     # check that stop(1) was called
15857     (check-ints-equal *(edx+4) 2 "F - test-convert-float-to-float: exit status")
15858     # don't restore from ebp
15859     81 0/subop/add %esp 8/imm32
15860     # . epilogue
15861     5d/pop-to-ebp
15862     c3/return
15864 #######################################################
15865 # Parsing
15866 #######################################################
15868 == data
15870 # Global state added to each var record when parsing a function
15871 Next-block-index:  # (addr int)
15872     1/imm32
15874 Curr-block-depth:  # (addr int)
15875     1/imm32
15877 == code
15879 parse-mu:  # in: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
15880     # pseudocode
15881     #   var curr-function: (addr handle function) = Program->functions
15882     #   var curr-signature: (addr handle function) = Program->signatures
15883     #   var curr-type: (addr handle typeinfo) = Program->types
15884     #   var line: (stream byte 512)
15885     #   var word-slice: slice
15886     #   while true                                  # line loop
15887     #     clear-stream(line)
15888     #     read-line-buffered(in, line)
15889     #     if (line->write == 0) break               # end of file
15890     #     word-slice = next-mu-token(line)
15891     #     if slice-empty?(word-slice)               # end of line
15892     #       continue
15893     #     else if slice-starts-with?(word-slice, "#")  # comment
15894     #       continue                                # end of line
15895     #     else if slice-equal?(word-slice, "fn")
15896     #       var new-function: (handle function) = allocate(function)
15897     #       var vars: (stack live-var 256)
15898     #       populate-mu-function-header(line, new-function, vars)
15899     #       populate-mu-function-body(in, new-function, vars)
15900     #       assert(vars->top == 0)
15901     #       *curr-function = new-function
15902     #       curr-function = &new-function->next
15903     #     else if slice-equal?(word-slice, "sig")
15904     #       var new-function: (handle function) = allocate(function)
15905     #       populate-mu-function-signature(line, new-function)
15906     #       *curr-signature = new-function
15907     #       curr-signature = &new-function->next
15908     #     else if slice-equal?(word-slice, "type")
15909     #       word-slice = next-mu-token(line)
15910     #       type-id = pos-or-insert-slice(Type-id, word-slice)
15911     #       var new-type: (handle typeinfo) = find-or-create-typeinfo(type-id)
15912     #       assert(next-word(line) == "{")
15913     #       populate-mu-type(in, new-type)
15914     #     else
15915     #       abort()
15916     #
15917     # . prologue
15918     55/push-ebp
15919     89/<- %ebp 4/r32/esp
15920     # var curr-signature: (addr handle function) at *(ebp-4)
15921     68/push _Program-signatures/imm32
15922     # . save registers
15923     50/push-eax
15924     51/push-ecx
15925     52/push-edx
15926     53/push-ebx
15927     56/push-esi
15928     57/push-edi
15929     # var line/ecx: (stream byte 512)
15930     81 5/subop/subtract %esp 0x200/imm32
15931     68/push 0x200/imm32/size
15932     68/push 0/imm32/read
15933     68/push 0/imm32/write
15934     89/<- %ecx 4/r32/esp
15935     # var word-slice/edx: slice
15936     68/push 0/imm32/end
15937     68/push 0/imm32/start
15938     89/<- %edx 4/r32/esp
15939     # var curr-function/edi: (addr handle function)
15940     bf/copy-to-edi _Program-functions/imm32
15941     # var vars/ebx: (stack live-var 256)
15942     81 5/subop/subtract %esp 0xc00/imm32
15943     68/push 0xc00/imm32/size
15944     68/push 0/imm32/top
15945     89/<- %ebx 4/r32/esp
15946     {
15947 $parse-mu:line-loop:
15948       (clear-stream %ecx)
15949       (read-line-buffered *(ebp+8) %ecx)
15950       # if (line->write == 0) break
15951       81 7/subop/compare *ecx 0/imm32
15952       0f 84/jump-if-= break/disp32
15953 #?       # dump line {{{
15954 #?       (write 2 "parse-mu: ^")
15955 #?       (write-stream 2 %ecx)
15956 #?       (write 2 "$\n")
15957 #?       (rewind-stream %ecx)
15958 #?       # }}}
15959       (next-mu-token %ecx %edx)
15960       # if slice-empty?(word-slice) continue
15961       (slice-empty? %edx)  # => eax
15962       3d/compare-eax-and 0/imm32/false
15963       0f 85/jump-if-!= loop/disp32
15964       # if (*word-slice->start == "#") continue
15965       # . eax = *word-slice->start
15966       8b/-> *edx 0/r32/eax
15967       8a/copy-byte *eax 0/r32/AL
15968       25/and-eax-with 0xff/imm32
15969       # . if (eax == '#') continue
15970       3d/compare-eax-and 0x23/imm32/hash
15971       0f 84/jump-if-= loop/disp32
15972       # if (slice-equal?(word-slice, "fn")) parse a function
15973       {
15974 $parse-mu:fn:
15975         (slice-equal? %edx "fn")  # => eax
15976         3d/compare-eax-and 0/imm32/false
15977         0f 84/jump-if-= break/disp32
15978         # var new-function/esi: (handle function)
15979         68/push 0/imm32
15980         68/push 0/imm32
15981         89/<- %esi 4/r32/esp
15982         # populate-mu-function(line, in, vars, new-function)
15983         (allocate Heap *Function-size %esi)
15984         # var new-function-addr/eax: (addr function)
15985         (lookup *esi *(esi+4))  # => eax
15986         # initialize vars
15987         (clear-stack %ebx)
15988         #
15989         (populate-mu-function-header %ecx %eax %ebx *(ebp+0xc) *(ebp+0x10))
15990         (populate-mu-function-body *(ebp+8) %eax %ebx *(ebp+0xc) *(ebp+0x10))
15991         # *curr-function = new-function
15992         8b/-> *esi 0/r32/eax
15993         89/<- *edi 0/r32/eax
15994         8b/-> *(esi+4) 0/r32/eax
15995         89/<- *(edi+4) 0/r32/eax
15996         # curr-function = &new-function->next
15997         # . var tmp/eax: (addr function) = lookup(new-function)
15998         (lookup *esi *(esi+4))  # => eax
15999         # . curr-function = &tmp->next
16000         8d/copy-address *(eax+0x20) 7/r32/edi  # Function-next
16001         # reclaim new-function
16002         81 0/subop/add %esp 8/imm32
16003         #
16004         e9/jump $parse-mu:line-loop/disp32
16005       }
16006       # if (slice-equal?(word-slice, "sig")) parse a function signature
16007       # Function signatures are for providing types to SubX functions.
16008       {
16009 $parse-mu:sig:
16010         (slice-equal? %edx "sig")  # => eax
16011         3d/compare-eax-and 0/imm32/false
16012         0f 84/jump-if-= break/disp32
16013         # edi = curr-function
16014         57/push-edi
16015         8b/-> *(ebp-4) 7/r32/edi
16016         # var new-function/esi: (handle function)
16017         68/push 0/imm32
16018         68/push 0/imm32
16019         89/<- %esi 4/r32/esp
16020         # populate-mu-function(line, in, vars, new-function)
16021         (allocate Heap *Function-size %esi)
16022         # var new-function-addr/eax: (addr function)
16023         (lookup *esi *(esi+4))  # => eax
16024         #
16025         (populate-mu-function-signature %ecx %eax *(ebp+0xc) *(ebp+0x10))
16026         # *curr-signature = new-function
16027         8b/-> *esi 0/r32/eax
16028         89/<- *edi 0/r32/eax
16029         8b/-> *(esi+4) 0/r32/eax
16030         89/<- *(edi+4) 0/r32/eax
16031         # curr-signature = &new-function->next
16032         # . var tmp/eax: (addr function) = lookup(new-function)
16033         (lookup *esi *(esi+4))  # => eax
16034         # . curr-function = &tmp->next
16035         8d/copy-address *(eax+0x20) 7/r32/edi  # Function-next
16036         # reclaim new-function
16037         81 0/subop/add %esp 8/imm32
16038         # save curr-function
16039         89/<- *(ebp-4) 7/r32/edi
16040         # restore edi
16041         5f/pop-to-edi
16042         #
16043         e9/jump $parse-mu:line-loop/disp32
16044       }
16045       # if (slice-equal?(word-slice, "type")) parse a type (struct/record) definition
16046       {
16047 $parse-mu:type:
16048         (slice-equal? %edx "type")  # => eax
16049         3d/compare-eax-and 0/imm32
16050         0f 84/jump-if-= break/disp32
16051         (next-mu-token %ecx %edx)
16052         # var type-id/eax: int
16053         (pos-or-insert-slice Type-id %edx)  # => eax
16054         # spill
16055         51/push-ecx
16056         # var new-type/ecx: (handle typeinfo)
16057         68/push 0/imm32
16058         68/push 0/imm32
16059         89/<- %ecx 4/r32/esp
16060         (find-or-create-typeinfo %eax %ecx)
16061         #
16062         (lookup *ecx *(ecx+4))  # => eax
16063         # TODO: ensure that 'line' has nothing else but '{'
16064 #? (dump-typeinfos "=== aaa\n")
16065         (populate-mu-type *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))  # => eax
16066 #? (dump-typeinfos "=== zzz\n")
16067         # reclaim new-type
16068         81 0/subop/add %esp 8/imm32
16069         # restore
16070         59/pop-to-ecx
16071         e9/jump $parse-mu:line-loop/disp32
16072       }
16073       # otherwise abort
16074       e9/jump $parse-mu:error1/disp32
16075     } # end line loop
16076 $parse-mu:end:
16077     # . reclaim locals
16078     81 0/subop/add %esp 0x20c/imm32  # line
16079     81 0/subop/add %esp 0xc08/imm32  # vars
16080     81 0/subop/add %esp 8/imm32
16081     # . restore registers
16082     5f/pop-to-edi
16083     5e/pop-to-esi
16084     5b/pop-to-ebx
16085     5a/pop-to-edx
16086     59/pop-to-ecx
16087     58/pop-to-eax
16088     # . reclaim local
16089     81 0/subop/add %esp 4/imm32
16090     # . epilogue
16091     89/<- %esp 5/r32/ebp
16092     5d/pop-to-ebp
16093     c3/return
16095 $parse-mu:error1:
16096     # error("unexpected top-level command: " word-slice "\n")
16097     (write-buffered *(ebp+0xc) "unexpected top-level command: ")
16098     (write-slice-buffered *(ebp+0xc) %edx)
16099     (write-buffered *(ebp+0xc) "\n")
16100     (flush *(ebp+0xc))
16101     (stop *(ebp+0x10) 1)
16102     # never gets here
16104 $parse-mu:error2:
16105     # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n")
16106     (write-int32-hex-buffered *(ebp+0xc) *ebx)
16107     (write-buffered *(ebp+0xc) " vars not reclaimed after fn '")
16108     (write-slice-buffered *(ebp+0xc) *eax)  # Function-name
16109     (write-buffered *(ebp+0xc) "'\n")
16110     (flush *(ebp+0xc))
16111     (stop *(ebp+0x10) 1)
16112     # never gets here
16114 # scenarios considered:
16115 # ✗ fn foo  # no block
16116 # ✓ fn foo {
16117 # ✗ fn foo { {
16118 # ✗ fn foo { }
16119 # ✗ fn foo { } {
16120 # ✗ fn foo x {
16121 # ✗ fn foo x: {
16122 # ✓ fn foo x: int {
16123 # ✓ fn foo x: int {
16124 # ✓ fn foo x: int -> _/eax: int {
16125 # TODO:
16126 #   disallow outputs of type `(... addr ...)`
16127 #   disallow inputs of type `(... addr ... addr ...)`
16128 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)
16129     # pseudocode:
16130     #   var word-slice: slice
16131     #   next-mu-token(first-line, word-slice)
16132     #   if slice-empty?(word-slice) abort
16133     #   assert(word-slice not in '{' '}' '->')
16134     #   out->name = slice-to-string(word-slice)
16135     #   ## inouts
16136     #   while true
16137     #     word-slice = next-mu-token(first-line)
16138     #     if slice-empty?(word-slice) abort
16139     #     if (word-slice == '{') goto done
16140     #     if (word-slice == '->') break
16141     #     assert(word-slice != '}')
16142     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
16143     #     assert(v->register == null)
16144     #     # v->block-depth is implicitly 0
16145     #     out->inouts = append(v, out->inouts)
16146     #     push(vars, {v, false})
16147     #   ## outputs
16148     #   while true
16149     #     word-slice = next-mu-token(first-line)
16150     #     if slice-empty?(word-slice) abort
16151     #     if (word-slice == '{') break
16152     #     assert(word-slice not in '}' '->')
16153     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
16154     #     assert(v->register != null)
16155     #     assert(v->name == "_")
16156     #     out->outputs = append(v, out->outputs)
16157     #   done:
16158     #
16159     # . prologue
16160     55/push-ebp
16161     89/<- %ebp 4/r32/esp
16162     # . save registers
16163     50/push-eax
16164     51/push-ecx
16165     52/push-edx
16166     53/push-ebx
16167     57/push-edi
16168     # edi = out
16169     8b/-> *(ebp+0xc) 7/r32/edi
16170     # var word-slice/ecx: slice
16171     68/push 0/imm32/end
16172     68/push 0/imm32/start
16173     89/<- %ecx 4/r32/esp
16174     # var v/ebx: (handle var)
16175     68/push 0/imm32
16176     68/push 0/imm32
16177     89/<- %ebx 4/r32/esp
16178     # read function name
16179     (next-mu-token *(ebp+8) %ecx)
16180     # error checking
16181     # if slice-empty?(word-slice) abort
16182     (slice-empty? %ecx)  # => eax
16183     3d/compare-eax-and 0/imm32/false
16184     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
16185     # if (word-slice == '{') abort
16186     (slice-equal? %ecx "{")   # => eax
16187     3d/compare-eax-and 0/imm32/false
16188     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
16189     # if (word-slice == '->') abort
16190     (slice-equal? %ecx "->")   # => eax
16191     3d/compare-eax-and 0/imm32/false
16192     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
16193     # if (word-slice == '}') abort
16194     (slice-equal? %ecx "}")   # => eax
16195     3d/compare-eax-and 0/imm32/false
16196     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
16197     # if word-slice already defined, abort
16198     (function-exists? %ecx)  # => eax
16199     3d/compare-eax-and 0/imm32/false
16200     0f 85/jump-if-!= $populate-mu-function-header:error-duplicate/disp32
16201     #
16202     (slice-starts-with? %ecx "break")  # => eax
16203     3d/compare-eax-and 0/imm32/false
16204     0f 85/jump-if-!= $populate-mu-function-header:error-break/disp32
16205     (slice-starts-with? %ecx "loop")  # => eax
16206     3d/compare-eax-and 0/imm32/false
16207     0f 85/jump-if-!= $populate-mu-function-header:error-loop/disp32
16208     (slice-equal? %ecx "lookup")  # => eax
16209     3d/compare-eax-and 0/imm32/false
16210     0f 85/jump-if-!= $populate-mu-function-header:error-lookup/disp32
16211     # save function name
16212     (slice-to-string Heap %ecx %edi)  # Function-name
16213     # save function inouts
16214     {
16215 $populate-mu-function-header:check-for-inout:
16216       (next-mu-token *(ebp+8) %ecx)
16217       # if slice-empty?(word-slice) abort
16218       (slice-empty? %ecx)  # => eax
16219       3d/compare-eax-and 0/imm32/false
16220       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
16221       # if (word-slice == '{') goto done
16222       (slice-equal? %ecx "{")   # => eax
16223       3d/compare-eax-and 0/imm32/false
16224       0f 85/jump-if-!= $populate-mu-function-header:done/disp32
16225       # if (word-slice == '->') break
16226       (slice-equal? %ecx "->")   # => eax
16227       3d/compare-eax-and 0/imm32/false
16228       0f 85/jump-if-!= break/disp32
16229       # if (word-slice == '}') abort
16230       (slice-equal? %ecx "}")   # => eax
16231       3d/compare-eax-and 0/imm32/false
16232       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
16233       # v = parse-var-with-type(word-slice, first-line)
16234       (lookup *edi *(edi+4))  # Function-name Function-name => eax
16235       (parse-var-with-type %ecx *(ebp+8) %ebx %eax *(ebp+0x14) *(ebp+0x18))
16236       # if (v->register != null) abort
16237       # . eax: (addr var) = lookup(v)
16238       (lookup *ebx *(ebx+4))  # => eax
16239       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
16240       0f 85/jump-if-!= $populate-mu-function-header:error2/disp32
16241       # if function name is not "main"
16242       #    and v->type contains an 'addr' anywhere except the start, abort
16243       {
16244         (lookup *edi *(edi+4))  # Function-name Function-name => eax
16245         (string-equal? %eax "main")  # => eax
16246         3d/compare-eax-and 0/imm32/false
16247         75/jump-if-!= break/disp8
16248         (lookup *ebx *(ebx+4))  # => eax
16249         (addr-payload-contains-addr? %eax)  # => eax
16250         3d/compare-eax-and 0/imm32/false
16251         0f 85/jump-if-!= $populate-mu-function-header:error-nested-addr-inout/disp32
16252       }
16253       # v->block-depth is implicitly 0
16254       #
16255       # out->inouts = append(v, out->inouts)
16256       8d/copy-address *(edi+8) 0/r32/eax  # Function-inouts
16257       (append-list Heap  *ebx *(ebx+4)  *(edi+8) *(edi+0xc)  %eax)  # Function-inouts, Function-inouts
16258       # push(vars, {v, false})
16259       (push *(ebp+0x10) *ebx)
16260       (push *(ebp+0x10) *(ebx+4))
16261       (push *(ebp+0x10) 0)  # false
16262       #
16263       e9/jump loop/disp32
16264     }
16265     # save function outputs
16266     {
16267 $populate-mu-function-header:check-for-out:
16268       (next-mu-token *(ebp+8) %ecx)
16269       # if slice-empty?(word-slice) abort
16270       (slice-empty? %ecx)  # => eax
16271       3d/compare-eax-and 0/imm32/false
16272       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
16273       # if (word-slice == '{') break
16274       (slice-equal? %ecx "{")   # => eax
16275       3d/compare-eax-and 0/imm32/false
16276       0f 85/jump-if-!= break/disp32
16277       # if (word-slice == '->') abort
16278       (slice-equal? %ecx "->")   # => eax
16279       3d/compare-eax-and 0/imm32/false
16280       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
16281       # if (word-slice == '}') abort
16282       (slice-equal? %ecx "}")   # => eax
16283       3d/compare-eax-and 0/imm32/false
16284       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
16285       # v = parse-var-with-type(word-slice, first-line)
16286       (lookup *edi *(edi+4))  # Function-name Function-name => eax
16287       (parse-var-with-type %ecx *(ebp+8) %ebx %eax *(ebp+0x14) *(ebp+0x18))
16288       # assert(var->register != null)
16289       # . eax: (addr var) = lookup(v)
16290       (lookup *ebx *(ebx+4))  # => eax
16291       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
16292       0f 84/jump-if-= $populate-mu-function-header:error3/disp32
16293       # if (var->name != "_") abort
16294       (lookup *eax *(eax+4))  # Var-name Var-name => eax
16295       (string-equal? %eax "_")  # => eax
16296       3d/compare-eax-and 0/imm32/false
16297       0f 84/jump-if-= $populate-mu-function-header:error4/disp32
16298       # if v->type is an addr, abort
16299       (lookup *ebx *(ebx+4))  # => eax
16300       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
16301       (mu-addr-type? %eax)  # => eax
16302       3d/compare-eax-and 0/imm32/false
16303       0f 85/jump-if-!= $populate-mu-function-header:error-addr-output/disp32
16304       # out->outputs = append(v, out->outputs)
16305       8d/copy-address *(edi+0x10) 0/r32/eax  # Function-outputs
16306       (append-list Heap  *ebx *(ebx+4)  *(edi+0x10) *(edi+0x14)  %eax)  # Function-outputs, Function-outputs
16307       #
16308       e9/jump loop/disp32
16309     }
16310 $populate-mu-function-header:done:
16311     (check-no-tokens-left *(ebp+8))
16312 $populate-mu-function-header:end:
16313     # . reclaim locals
16314     81 0/subop/add %esp 0x10/imm32
16315     # . restore registers
16316     5f/pop-to-edi
16317     5b/pop-to-ebx
16318     5a/pop-to-edx
16319     59/pop-to-ecx
16320     58/pop-to-eax
16321     # . epilogue
16322     89/<- %esp 5/r32/ebp
16323     5d/pop-to-ebp
16324     c3/return
16326 $populate-mu-function-header:error1:
16327     # error("function header not in form 'fn <name> {'")
16328     (write-buffered *(ebp+0x14) "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '")
16329     (flush *(ebp+0x14))
16330     (rewind-stream *(ebp+8))
16331     (write-stream-data *(ebp+0x14) *(ebp+8))
16332     (write-buffered *(ebp+0x14) "'\n")
16333     (flush *(ebp+0x14))
16334     (stop *(ebp+0x18) 1)
16335     # never gets here
16337 $populate-mu-function-header:error2:
16338     # error("fn " fn ": function inout '" var "' cannot be in a register")
16339     (write-buffered *(ebp+0x14) "fn ")
16340     50/push-eax
16341     (lookup *edi *(edi+4))  # Function-name Function-name => eax
16342     (write-buffered *(ebp+0x14) %eax)
16343     58/pop-to-eax
16344     (write-buffered *(ebp+0x14) ": function inout '")
16345     (lookup *eax *(eax+4))  # Var-name Var-name => eax
16346     (write-buffered *(ebp+0x14) %eax)
16347     (write-buffered *(ebp+0x14) "' cannot be in a register")
16348     (flush *(ebp+0x14))
16349     (stop *(ebp+0x18) 1)
16350     # never gets here
16352 $populate-mu-function-header:error3:
16353     # error("fn " fn ": function output '" var "' must be in a register")
16354     (write-buffered *(ebp+0x14) "fn ")
16355     50/push-eax
16356     (lookup *edi *(edi+4))  # Function-name Function-name => eax
16357     (write-buffered *(ebp+0x14) %eax)
16358     58/pop-to-eax
16359     (write-buffered *(ebp+0x14) ": function output '")
16360     (lookup *ebx *(ebx+4))  # => eax
16361     (lookup *eax *(eax+4))  # Var-name Var-name => eax
16362     (write-buffered *(ebp+0x14) %eax)
16363     (write-buffered *(ebp+0x14) "' must be in a register, in instruction '")
16364     (rewind-stream *(ebp+8))
16365     (write-stream-data *(ebp+0x14) *(ebp+8))
16366     (write-buffered *(ebp+0x14) "'\n")
16367     (flush *(ebp+0x14))
16368     (stop *(ebp+0x18) 1)
16369     # never gets here
16371 $populate-mu-function-header:error4:
16372     # error("fn " fn ": function outputs cannot be named; rename '" var "' in the header to '_'")
16373     (write-buffered *(ebp+0x14) "fn ")
16374     50/push-eax
16375     (lookup *edi *(edi+4))  # Function-name Function-name => eax
16376     (write-buffered *(ebp+0x14) %eax)
16377     58/pop-to-eax
16378     (write-buffered *(ebp+0x14) ": function outputs cannot be named; rename '")
16379     (lookup *ebx *(ebx+4))  # => eax
16380     (lookup *eax *(eax+4))  # Var-name Var-name => eax
16381     (write-buffered *(ebp+0x14) %eax)
16382     (write-buffered *(ebp+0x14) "' in the header to '_'\n")
16383     (flush *(ebp+0x14))
16384     (stop *(ebp+0x18) 1)
16385     # never gets here
16387 $populate-mu-function-header:error-duplicate:
16388     (write-buffered *(ebp+0x14) "fn ")
16389     (write-slice-buffered *(ebp+0x14) %ecx)
16390     (write-buffered *(ebp+0x14) " defined more than once\n")
16391     (flush *(ebp+0x14))
16392     (stop *(ebp+0x18) 1)
16393     # never gets here
16395 $populate-mu-function-header:error-break:
16396     (write-buffered *(ebp+0x14) "Sorry, I've reserved all function names starting with 'break' for now. Please contact mu@akkartik.com.\n")
16397     (flush *(ebp+0x14))
16398     (stop *(ebp+0x18) 1)
16399     # never gets here
16401 $populate-mu-function-header:error-loop:
16402     (write-buffered *(ebp+0x14) "Sorry, I've reserved all function names starting with 'loop' for now. Please contact mu@akkartik.com.\n")
16403     (flush *(ebp+0x14))
16404     (stop *(ebp+0x18) 1)
16405     # never gets here
16407 $populate-mu-function-header:error-lookup:
16408     (write-buffered *(ebp+0x14) "cannot define a function called 'lookup'\n")
16409     (flush *(ebp+0x14))
16410     (stop *(ebp+0x18) 1)
16411     # never gets here
16413 $populate-mu-function-header:error-addr-output:
16414     # error("fn " fn ": output cannot have an addr type; that could allow unsafe addresses to escape the function")
16415     (write-buffered *(ebp+0x14) "fn ")
16416     50/push-eax
16417     (lookup *edi *(edi+4))  # Function-name Function-name => eax
16418     (write-buffered *(ebp+0x14) %eax)
16419     58/pop-to-eax
16420     (write-buffered *(ebp+0x14) ": output cannot have an addr type; that could allow unsafe addresses to escape the function\n")
16421     (flush *(ebp+0x14))
16422     (stop *(ebp+0x18) 1)
16423     # never gets here
16425 $populate-mu-function-header:error-nested-addr-inout:
16426     # error("fn " fn ": inout '" var "' cannot contain 'addr' anywhere in the type except the first word; that could allow unsafe addresses to escape the function")
16427     (write-buffered *(ebp+0x14) "fn ")
16428     (lookup *edi *(edi+4))  # Function-name Function-name => eax
16429     (write-buffered *(ebp+0x14) %eax)
16430     (write-buffered *(ebp+0x14) ": inout '")
16431     (lookup *ebx *(ebx+4))  # => eax
16432     (lookup *eax *(eax+4))  # Var-name Var-name => eax
16433     (write-buffered *(ebp+0x14) %eax)
16434     (write-buffered *(ebp+0x14) "' cannot contain 'addr' anywhere in the type except the first word; that could allow unsafe addresses to escape the function\n")
16435     (flush *(ebp+0x14))
16436     (stop *(ebp+0x18) 1)
16437     # never gets here
16439 # scenarios considered:
16440 # ✓ fn foo
16441 # ✗ fn foo {
16442 # ✓ fn foo x
16443 # ✓ fn foo x: int
16444 # ✓ fn foo x: int -> _/eax: int
16445 # TODO:
16446 #   disallow outputs of type `(... addr ...)`
16447 #   disallow inputs of type `(... addr ... addr ...)`
16448 populate-mu-function-signature:  # first-line: (addr stream byte), out: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
16449     # pseudocode:
16450     #   var word-slice: slice
16451     #   next-mu-token(first-line, word-slice)
16452     #   assert(word-slice not in '{' '}' '->')
16453     #   out->name = slice-to-string(word-slice)
16454     #   ## inouts
16455     #   while true
16456     #     word-slice = next-mu-token(first-line)
16457     #     if slice-empty?(word-slice) break
16458     #     if (word-slice == '->') break
16459     #     assert(word-slice not in '{' '}')
16460     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
16461     #     assert(v->register == null)
16462     #     # v->block-depth is implicitly 0
16463     #     out->inouts = append(v, out->inouts)
16464     #   ## outputs
16465     #   while true
16466     #     word-slice = next-mu-token(first-line)
16467     #     if slice-empty?(word-slice) break
16468     #     assert(word-slice not in '{' '}' '->')
16469     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
16470     #     assert(v->register != null)
16471     #     out->outputs = append(v, out->outputs)
16472     #
16473     # . prologue
16474     55/push-ebp
16475     89/<- %ebp 4/r32/esp
16476     # . save registers
16477     50/push-eax
16478     51/push-ecx
16479     52/push-edx
16480     53/push-ebx
16481     57/push-edi
16482     # edi = out
16483     8b/-> *(ebp+0xc) 7/r32/edi
16484     # var word-slice/ecx: slice
16485     68/push 0/imm32/end
16486     68/push 0/imm32/start
16487     89/<- %ecx 4/r32/esp
16488     # var v/ebx: (handle var)
16489     68/push 0/imm32
16490     68/push 0/imm32
16491     89/<- %ebx 4/r32/esp
16492     # read function name
16493     (next-mu-token *(ebp+8) %ecx)
16494     # error checking
16495     # if (word-slice == '{') abort
16496     (slice-equal? %ecx "{")   # => eax
16497     3d/compare-eax-and 0/imm32/false
16498     0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
16499     # if (word-slice == '->') abort
16500     (slice-equal? %ecx "->")   # => eax
16501     3d/compare-eax-and 0/imm32/false
16502     0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
16503     # if (word-slice == '}') abort
16504     (slice-equal? %ecx "}")   # => eax
16505     3d/compare-eax-and 0/imm32/false
16506     0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
16507     # if word-slice already defined, abort
16508     (function-exists? %ecx)  # => eax
16509     3d/compare-eax-and 0/imm32/false
16510     0f 85/jump-if-!= $populate-mu-function-signature:error-duplicate/disp32
16511     #
16512     (slice-starts-with? %ecx "break")  # => eax
16513     3d/compare-eax-and 0/imm32/false
16514     0f 85/jump-if-!= $populate-mu-function-signature:error-break/disp32
16515     (slice-starts-with? %ecx "loop")  # => eax
16516     3d/compare-eax-and 0/imm32/false
16517     0f 85/jump-if-!= $populate-mu-function-signature:error-loop/disp32
16518     # save function name
16519     (slice-to-string Heap %ecx %edi)  # Function-name
16520     # save function inouts
16521     {
16522 $populate-mu-function-signature:check-for-inout:
16523       (next-mu-token *(ebp+8) %ecx)
16524       (slice-empty? %ecx)  # => eax
16525       3d/compare-eax-and 0/imm32/false
16526       0f 85/jump-if-!= break/disp32
16527       # if (word-slice == '->') break
16528       (slice-equal? %ecx "->")   # => eax
16529       3d/compare-eax-and 0/imm32/false
16530       0f 85/jump-if-!= break/disp32
16531       # if (word-slice == '{') abort
16532       (slice-equal? %ecx "{")   # => eax
16533       3d/compare-eax-and 0/imm32/false
16534       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
16535       # if (word-slice == '}') abort
16536       (slice-equal? %ecx "}")   # => eax
16537       3d/compare-eax-and 0/imm32/false
16538       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
16539       # v = parse-var-with-type(word-slice, first-line)
16540       (lookup *edi *(edi+4))  # Function-name Function-name => eax
16541       (parse-var-with-type %ecx *(ebp+8) %ebx %eax *(ebp+0x10) *(ebp+0x14))
16542       # if (v->register != null) abort
16543       # . eax: (addr var) = lookup(v)
16544       (lookup *ebx *(ebx+4))  # => eax
16545       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
16546       0f 85/jump-if-!= $populate-mu-function-signature:error2/disp32
16547       # if function name is not "main"
16548       #    and v->type contains an 'addr' anywhere except the start, abort
16549       {
16550         (lookup *edi *(edi+4))  # Function-name Function-name => eax
16551         (string-equal? %eax "main")  # => eax
16552         3d/compare-eax-and 0/imm32/false
16553         75/jump-if-!= break/disp8
16554         (lookup *ebx *(ebx+4))  # => eax
16555         (addr-payload-contains-addr? %eax)  # => eax
16556         3d/compare-eax-and 0/imm32/false
16557         0f 85/jump-if-!= $populate-mu-function-signature:error-nested-addr-inout/disp32
16558       }
16559       # assert(v->register == null)
16560       # . eax: (addr var) = lookup(v)
16561       (lookup *ebx *(ebx+4))  # => eax
16562       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
16563       0f 85/jump-if-!= $populate-mu-function-signature:error2/disp32
16564       # v->block-depth is implicitly 0
16565       #
16566       # out->inouts = append(v, out->inouts)
16567       8d/copy-address *(edi+8) 0/r32/eax  # Function-inouts
16568       (append-list Heap  *ebx *(ebx+4)  *(edi+8) *(edi+0xc)  %eax)  # Function-inouts, Function-inouts
16569       #
16570       e9/jump loop/disp32
16571     }
16572     # save function outputs
16573     {
16574 $populate-mu-function-signature:check-for-out:
16575       (next-mu-token *(ebp+8) %ecx)
16576       (slice-empty? %ecx)  # => eax
16577       3d/compare-eax-and 0/imm32/false
16578       0f 85/jump-if-!= break/disp32
16579       # if (word-slice == '{') abort
16580       (slice-equal? %ecx "{")   # => eax
16581       3d/compare-eax-and 0/imm32/false
16582       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
16583       # if (word-slice == '->') abort
16584       (slice-equal? %ecx "->")   # => eax
16585       3d/compare-eax-and 0/imm32/false
16586       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
16587       # if (word-slice == '}') abort
16588       (slice-equal? %ecx "}")   # => eax
16589       3d/compare-eax-and 0/imm32/false
16590       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
16591       # v = parse-var-with-type(word-slice, first-line)
16592       (lookup *edi *(edi+4))  # Function-name Function-name => eax
16593       (parse-var-with-type %ecx *(ebp+8) %ebx %eax *(ebp+0x10) *(ebp+0x14))
16594       # assert(var->register != null)
16595       # . eax: (addr var) = lookup(v)
16596       (lookup *ebx *(ebx+4))  # => eax
16597       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
16598       0f 84/jump-if-= $populate-mu-function-signature:error3/disp32
16599       # if (var->name != "_") abort
16600       (lookup *eax *(eax+4))  # Var-name Var-name => eax
16601       (string-equal? %eax "_")  # => eax
16602       3d/compare-eax-and 0/imm32/false
16603       0f 84/jump-if-= $populate-mu-function-signature:error4/disp32
16604       # if function name is not "lookup"
16605       #    and v->type is an addr, abort
16606       {
16607         (lookup *edi *(edi+4))  # Function-name Function-name => eax
16608         (string-equal? %eax "lookup")  # => eax
16609         3d/compare-eax-and 0/imm32/false
16610         75/jump-if-!= break/disp8
16611         (lookup *ebx *(ebx+4))  # => eax
16612         (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
16613         (mu-addr-type? %eax)  # => eax
16614         3d/compare-eax-and 0/imm32/false
16615         0f 85/jump-if-!= $populate-mu-function-signature:error-addr-output/disp32
16616       }
16617       # out->outputs = append(v, out->outputs)
16618       8d/copy-address *(edi+0x10) 0/r32/eax  # Function-outputs
16619       (append-list Heap  *ebx *(ebx+4)  *(edi+0x10) *(edi+0x14)  %eax)  # Function-outputs, Function-outputs
16620       #
16621       e9/jump loop/disp32
16622     }
16623 $populate-mu-function-signature:done:
16624     (check-no-tokens-left *(ebp+8))
16625 $populate-mu-function-signature:end:
16626     # . reclaim locals
16627     81 0/subop/add %esp 0x10/imm32
16628     # . restore registers
16629     5f/pop-to-edi
16630     5b/pop-to-ebx
16631     5a/pop-to-edx
16632     59/pop-to-ecx
16633     58/pop-to-eax
16634     # . epilogue
16635     89/<- %esp 5/r32/ebp
16636     5d/pop-to-ebp
16637     c3/return
16639 $populate-mu-function-signature:error1:
16640     # error("function signature not in form 'fn <name> {'")
16641     (write-buffered *(ebp+0x10) "function signature not in form 'fn <name> [inouts] [-> outputs] {' -- '")
16642     (flush *(ebp+0x10))
16643     (rewind-stream *(ebp+8))
16644     (write-stream-data *(ebp+0x10) *(ebp+8))
16645     (write-buffered *(ebp+0x10) "'\n")
16646     (flush *(ebp+0x10))
16647     (stop *(ebp+0x14) 1)
16648     # never gets here
16650 $populate-mu-function-signature:error2:
16651     # error("fn " fn ": function inout '" var "' cannot be in a register")
16652     (write-buffered *(ebp+0x10) "fn ")
16653     50/push-eax
16654     (lookup *edi *(edi+4))  # Function-name Function-name => eax
16655     (write-buffered *(ebp+0x10) %eax)
16656     58/pop-to-eax
16657     (write-buffered *(ebp+0x10) ": function inout '")
16658     (lookup *eax *(eax+4))  # Var-name Var-name => eax
16659     (write-buffered *(ebp+0x10) %eax)
16660     (write-buffered *(ebp+0x10) "' cannot be in a register")
16661     (flush *(ebp+0x10))
16662     (stop *(ebp+0x14) 1)
16663     # never gets here
16665 $populate-mu-function-signature:error3:
16666     # error("fn " fn ": function output '" var "' must be in a register")
16667     (write-buffered *(ebp+0x10) "fn ")
16668     50/push-eax
16669     (lookup *edi *(edi+4))  # Function-name Function-name => eax
16670     (write-buffered *(ebp+0x10) %eax)
16671     58/pop-to-eax
16672     (write-buffered *(ebp+0x10) ": function output '")
16673     (lookup *ebx *(ebx+4))  # => eax
16674     (lookup *eax *(eax+4))  # Var-name Var-name => eax
16675     (write-buffered *(ebp+0x10) %eax)
16676     (write-buffered *(ebp+0x10) "' must be in a register, in instruction '")
16677     (rewind-stream *(ebp+8))
16678     (write-stream-data *(ebp+0x10) *(ebp+8))
16679     (write-buffered *(ebp+0x10) "'\n")
16680     (flush *(ebp+0x10))
16681     (stop *(ebp+0x14) 1)
16682     # never gets here
16684 $populate-mu-function-signature:error4:
16685     # error("fn " fn ": function outputs cannot be named; rename '" var "' in the header to '_'")
16686     (write-buffered *(ebp+0x10) "fn ")
16687     50/push-eax
16688     (lookup *edi *(edi+4))  # Function-name Function-name => eax
16689     (write-buffered *(ebp+0x10) %eax)
16690     58/pop-to-eax
16691     (write-buffered *(ebp+0x10) ": function outputs cannot be named; rename '")
16692     (lookup *ebx *(ebx+4))  # => eax
16693     (lookup *eax *(eax+4))  # Var-name Var-name => eax
16694     (write-buffered *(ebp+0x10) %eax)
16695     (write-buffered *(ebp+0x10) "' in the header to '_'\n")
16696     (flush *(ebp+0x10))
16697     (stop *(ebp+0x14) 1)
16698     # never gets here
16700 $populate-mu-function-signature:error-duplicate:
16701     (write-buffered *(ebp+0x10) "fn ")
16702     (write-slice-buffered *(ebp+0x10) %ecx)
16703     (write-buffered *(ebp+0x10) " defined more than once\n")
16704     (flush *(ebp+0x10))
16705     (stop *(ebp+0x14) 1)
16706     # never gets here
16708 $populate-mu-function-signature:error-break:
16709     (write-buffered *(ebp+0x10) "Sorry, I've reserved all function names starting with 'break' for now. Please contact mu@akkartik.com.\n")
16710     (flush *(ebp+0x10))
16711     (stop *(ebp+0x14) 1)
16712     # never gets here
16714 $populate-mu-function-signature:error-loop:
16715     (write-buffered *(ebp+0x10) "Sorry, I've reserved all function names starting with 'loop' for now. Please contact mu@akkartik.com.\n")
16716     (flush *(ebp+0x10))
16717     (stop *(ebp+0x14) 1)
16718     # never gets here
16720 $populate-mu-function-signature:error-addr-output:
16721     # error("fn " fn ": output cannot have an addr type; that could allow unsafe addresses to escape the function")
16722     (write-buffered *(ebp+0x10) "fn ")
16723     50/push-eax
16724     (lookup *edi *(edi+4))  # Function-name Function-name => eax
16725     (write-buffered *(ebp+0x10) %eax)
16726     58/pop-to-eax
16727     (write-buffered *(ebp+0x10) ": output cannot have an addr type; that could allow unsafe addresses to escape the function\n")
16728     (flush *(ebp+0x10))
16729     (stop *(ebp+0x14) 1)
16730     # never gets here
16732 $populate-mu-function-signature:error-nested-addr-inout:
16733     # error("fn " fn ": inout '" var "' cannot contain 'addr' anywhere in the type except the first word; that could allow unsafe addresses to escape the function")
16734     (write-buffered *(ebp+0x10) "fn ")
16735     (lookup *edi *(edi+4))  # Function-name Function-name => eax
16736     (write-buffered *(ebp+0x10) %eax)
16737     (write-buffered *(ebp+0x10) ": inout '")
16738     (lookup *ebx *(ebx+4))  # => eax
16739     (lookup *eax *(eax+4))  # Var-name Var-name => eax
16740     (write-buffered *(ebp+0x10) %eax)
16741     (write-buffered *(ebp+0x10) "' cannot contain 'addr' anywhere in the type except the first word; that could allow unsafe addresses to escape the function\n")
16742     (flush *(ebp+0x10))
16743     (stop *(ebp+0x14) 1)
16744     # never gets here
16746 addr-payload-contains-addr?:  # v: (addr var) -> result/eax: boolean
16747     # . prologue
16748     55/push-ebp
16749     89/<- %ebp 4/r32/esp
16750     # var t/eax: (addr type-tree) = v->type
16751     8b/-> *(ebp+8) 0/r32/eax
16752     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
16753     # if t->right contains addr, return true
16754     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
16755     (type-tree-contains? %eax 2)  # addr => eax
16756     # we don't have to look at t->left as long as it's guaranteed to be an atom
16757 $addr-payload-contains-addr?:end:
16758     # . epilogue
16759     89/<- %esp 5/r32/ebp
16760     5d/pop-to-ebp
16761     c3/return
16763 type-tree-contains?:  # t: (addr type-tree), n: type-id -> result/eax: boolean
16764     # . prologue
16765     55/push-ebp
16766     89/<- %ebp 4/r32/esp
16767     # . save registers
16768     51/push-ecx
16769     # if t is null, return false
16770     8b/-> *(ebp+8) 0/r32/eax
16771     3d/compare-eax-and 0/imm32
16772     0f 84/jump-if-= $type-tree-contains?:end/disp32  # eax changes type
16773     # if t is an atom, return (t->value == n)
16774     81 7/subop/compare *eax 0/imm32/false
16775     {
16776       74/jump-if-= break/disp8
16777       8b/-> *(ebp+0xc) 1/r32/ecx
16778       39/compare *(eax+4) 1/r32/ecx  # Type-tree-value
16779       0f 94/set-if-= %al
16780       25/and-eax-with 0xff/imm32
16781       eb/jump $type-tree-contains?:end/disp8
16782     }
16783     # if t->left contains n, return true
16784     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
16785     (type-tree-contains? %eax *(ebp+0xc))  # => eax
16786     3d/compare-eax-and 0/imm32/false
16787     75/jump-if-!= $type-tree-contains?:end/disp8
16788     # otherwise return whether t->right contains n
16789     8b/-> *(ebp+8) 0/r32/eax
16790     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
16791     (type-tree-contains? %eax *(ebp+0xc))  # => eax
16792 $type-tree-contains?:end:
16793     # . restore registers
16794     59/pop-to-ecx
16795     # . epilogue
16796     89/<- %esp 5/r32/ebp
16797     5d/pop-to-ebp
16798     c3/return
16800 function-exists?:  # s: (addr slice) -> result/eax: boolean
16801     # . prologue
16802     55/push-ebp
16803     89/<- %ebp 4/r32/esp
16804     # . save registers
16805     51/push-ecx
16806     # var curr/ecx: (addr function) = functions
16807     (lookup *_Program-functions *_Program-functions->payload)  # => eax
16808     89/<- %ecx 0/r32/eax
16809     {
16810       # if (curr == null) break
16811       81 7/subop/compare %ecx 0/imm32
16812       74/jump-if-= break/disp8
16813       # if (curr->name == s) return true
16814       {
16815         (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
16816         (slice-equal? *(ebp+8) %eax)  # => eax
16817         3d/compare-eax-and 0/imm32/false
16818         74/jump-if-= break/disp8
16819         b8/copy-to-eax 1/imm32/true
16820         e9/jump $function-exists?:end/disp32
16821       }
16822       # curr = curr->next
16823       (lookup *(ecx+0x20) *(ecx+0x24))  # Function-next Function-next => eax
16824       89/<- %ecx 0/r32/eax
16825       #
16826       eb/jump loop/disp8
16827     }
16828     # var curr/ecx: (addr function) = signatures
16829     (lookup *_Program-signatures *_Program-signatures->payload)  # => eax
16830     89/<- %ecx 0/r32/eax
16831     {
16832       # if (curr == null) break
16833       81 7/subop/compare %ecx 0/imm32
16834       74/jump-if-= break/disp8
16835       # if (curr->name == s) return true
16836       {
16837         (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
16838         (slice-equal? *(ebp+8) %eax)  # => eax
16839         3d/compare-eax-and 0/imm32/false
16840         74/jump-if-= break/disp8
16841         b8/copy-to-eax 1/imm32/true
16842         eb/jump $function-exists?:end/disp8
16843       }
16844       # curr = curr->next
16845       (lookup *(ecx+0x20) *(ecx+0x24))  # Function-next Function-next => eax
16846       89/<- %ecx 0/r32/eax
16847       #
16848       eb/jump loop/disp8
16849     }
16850     # return false
16851     b8/copy-to-eax 0/imm32/false
16852 $function-exists?:end:
16853     # . restore registers
16854     59/pop-to-ecx
16855     # . epilogue
16856     89/<- %esp 5/r32/ebp
16857     5d/pop-to-ebp
16858     c3/return
16860 test-function-header-with-arg:
16861     # . prologue
16862     55/push-ebp
16863     89/<- %ebp 4/r32/esp
16864     # setup
16865     8b/-> *Primitive-type-ids 0/r32/eax
16866     89/<- *Type-id 0/r32/eax  # stream-write
16867     c7 0/subop/copy *_Program-functions 0/imm32
16868     c7 0/subop/copy *_Program-functions->payload 0/imm32
16869     c7 0/subop/copy *_Program-types 0/imm32
16870     c7 0/subop/copy *_Program-types->payload 0/imm32
16871     c7 0/subop/copy *_Program-signatures 0/imm32
16872     c7 0/subop/copy *_Program-signatures->payload 0/imm32
16873     (clear-stream _test-input-stream)
16874     (write _test-input-stream "foo n: int {\n")
16875     # var result/ecx: function
16876     2b/subtract *Function-size 4/r32/esp
16877     89/<- %ecx 4/r32/esp
16878     (zero-out %ecx *Function-size)
16879     # var vars/ebx: (stack live-var 16)
16880     81 5/subop/subtract %esp 0xc0/imm32
16881     68/push 0xc0/imm32/size
16882     68/push 0/imm32/top
16883     89/<- %ebx 4/r32/esp
16884     # convert
16885     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
16886     # check result->name
16887     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
16888     (check-strings-equal %eax "foo" "F - test-function-header-with-arg/name")
16889     # var v/edx: (addr var) = result->inouts->value
16890     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
16891     (lookup *eax *(eax+4))  # List-value List-value => eax
16892     89/<- %edx 0/r32/eax
16893     # check v->name
16894     (lookup *edx *(edx+4))  # Var-name Var-name => eax
16895     (check-strings-equal %eax "n" "F - test-function-header-with-arg/inout:0")
16896     # check v->type
16897     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
16898     (check-ints-equal *eax 1 "F - test-function-header-with-arg/inout:0/type:0")  # Type-tree-is-atom
16899     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-arg/inout:0/type:1")  # Type-tree-value
16900     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-arg/inout:0/type:2")  # Type-tree-right
16901     # . epilogue
16902     89/<- %esp 5/r32/ebp
16903     5d/pop-to-ebp
16904     c3/return
16906 test-function-header-with-multiple-args:
16907     # . prologue
16908     55/push-ebp
16909     89/<- %ebp 4/r32/esp
16910     # setup
16911     8b/-> *Primitive-type-ids 0/r32/eax
16912     89/<- *Type-id 0/r32/eax  # stream-write
16913     c7 0/subop/copy *_Program-functions 0/imm32
16914     c7 0/subop/copy *_Program-functions->payload 0/imm32
16915     c7 0/subop/copy *_Program-types 0/imm32
16916     c7 0/subop/copy *_Program-types->payload 0/imm32
16917     c7 0/subop/copy *_Program-signatures 0/imm32
16918     c7 0/subop/copy *_Program-signatures->payload 0/imm32
16919     (clear-stream _test-input-stream)
16920     (write _test-input-stream "foo a: int, b: int c: int {\n")
16921     # result/ecx: function
16922     2b/subtract *Function-size 4/r32/esp
16923     89/<- %ecx 4/r32/esp
16924     (zero-out %ecx *Function-size)
16925     # var vars/ebx: (stack live-var 16)
16926     81 5/subop/subtract %esp 0xc0/imm32
16927     68/push 0xc0/imm32/size
16928     68/push 0/imm32/top
16929     89/<- %ebx 4/r32/esp
16930     # convert
16931     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
16932     # check result->name
16933     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
16934     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args/name")
16935     # var inouts/edx: (addr list var) = lookup(result->inouts)
16936     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
16937     89/<- %edx 0/r32/eax
16938 $test-function-header-with-multiple-args:inout0:
16939     # var v/ebx: (addr var) = lookup(inouts->value)
16940     (lookup *edx *(edx+4))  # List-value List-value => eax
16941     89/<- %ebx 0/r32/eax
16942     # check v->name
16943     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
16944     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args/inout:0")  # Var-name
16945     # check v->type
16946     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
16947     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:0/type:0")  # Type-tree-is-atom
16948     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:0/type:1")  # Type-tree-value
16949     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:0/type:2")  # Type-tree-right
16950 $test-function-header-with-multiple-args:inout1:
16951     # inouts = lookup(inouts->next)
16952     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
16953     89/<- %edx 0/r32/eax
16954     # v = lookup(inouts->value)
16955     (lookup *edx *(edx+4))  # List-value List-value => eax
16956     89/<- %ebx 0/r32/eax
16957     # check v->name
16958     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
16959     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args/inout:1")  # Var-name
16960     # check v->type
16961     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
16962     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:1/type:0")  # Type-tree-is-atom
16963     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:1/type:1")  # Type-tree-value
16964     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:1/type:2")  # Type-tree-right
16965 $test-function-header-with-multiple-args:inout2:
16966     # inouts = lookup(inouts->next)
16967     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
16968     89/<- %edx 0/r32/eax
16969     # v = lookup(inouts->value)
16970     (lookup *edx *(edx+4))  # List-value List-value => eax
16971     89/<- %ebx 0/r32/eax
16972     # check v->name
16973     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
16974     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args/inout:2")  # Var-name
16975     # check v->type
16976     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
16977     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:2/type:0")  # Type-tree-is-atom
16978     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:2/type:1")  # Type-tree-value
16979     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:2/type:2")  # Type-tree-right
16980     # . epilogue
16981     89/<- %esp 5/r32/ebp
16982     5d/pop-to-ebp
16983     c3/return
16985 test-function-header-with-multiple-args-and-outputs:
16986     # . prologue
16987     55/push-ebp
16988     89/<- %ebp 4/r32/esp
16989     # setup
16990     8b/-> *Primitive-type-ids 0/r32/eax
16991     89/<- *Type-id 0/r32/eax  # stream-write
16992     c7 0/subop/copy *_Program-functions 0/imm32
16993     c7 0/subop/copy *_Program-functions->payload 0/imm32
16994     c7 0/subop/copy *_Program-types 0/imm32
16995     c7 0/subop/copy *_Program-types->payload 0/imm32
16996     c7 0/subop/copy *_Program-signatures 0/imm32
16997     c7 0/subop/copy *_Program-signatures->payload 0/imm32
16998     (clear-stream _test-input-stream)
16999     (write _test-input-stream "foo a: int, b: int, c: int -> _/ecx: int _/edx: int {\n")
17000     # result/ecx: function
17001     2b/subtract *Function-size 4/r32/esp
17002     89/<- %ecx 4/r32/esp
17003     (zero-out %ecx *Function-size)
17004     # var vars/ebx: (stack live-var 16)
17005     81 5/subop/subtract %esp 0xc0/imm32
17006     68/push 0xc0/imm32/size
17007     68/push 0/imm32/top
17008     89/<- %ebx 4/r32/esp
17009     # convert
17010     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
17011     # check result->name
17012     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
17013     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args-and-outputs/name")
17014     # var inouts/edx: (addr list var) = lookup(result->inouts)
17015     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
17016     89/<- %edx 0/r32/eax
17017 $test-function-header-with-multiple-args-and-outputs:inout0:
17018     # var v/ebx: (addr var) = lookup(inouts->value)
17019     (lookup *edx *(edx+4))  # List-value List-value => eax
17020     89/<- %ebx 0/r32/eax
17021     # check v->name
17022     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
17023     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args-and-outputs/inout:0")
17024     # check v->type
17025     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
17026     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:0")  # Type-tree-is-atom
17027     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1")  # Type-tree-value
17028     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:2")  # Type-tree-right
17029 $test-function-header-with-multiple-args-and-outputs:inout1:
17030     # inouts = lookup(inouts->next)
17031     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
17032     89/<- %edx 0/r32/eax
17033     # v = lookup(inouts->value)
17034     (lookup *edx *(edx+4))  # List-value List-value => eax
17035     89/<- %ebx 0/r32/eax
17036     # check v->name
17037     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
17038     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args-and-outputs/inout:1")
17039     # check v->type
17040     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
17041     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:0")  # Type-tree-is-atom
17042     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1")  # Type-tree-value
17043     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:2")  # Type-tree-right
17044 $test-function-header-with-multiple-args-and-outputs:inout2:
17045     # inouts = lookup(inouts->next)
17046     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
17047     89/<- %edx 0/r32/eax
17048     # v = lookup(inouts->value)
17049     (lookup *edx *(edx+4))  # List-value List-value => eax
17050     89/<- %ebx 0/r32/eax
17051     # check v->name
17052     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
17053     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args-and-outputs/inout:2")
17054     # check v->type
17055     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
17056     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:0")  # Type-tree-is-atom
17057     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1")  # Type-tree-value
17058     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:2")  # Type-tree-right
17059 $test-function-header-with-multiple-args-and-outputs:out0:
17060     # var outputs/edx: (addr list var) = lookup(result->outputs)
17061     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
17062     89/<- %edx 0/r32/eax
17063     # v = lookup(outputs->value)
17064     (lookup *edx *(edx+4))  # List-value List-value => eax
17065     89/<- %ebx 0/r32/eax
17066     # check v->name
17067     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
17068     (check-strings-equal %eax "_" "F - test-function-header-with-multiple-args-and-outputs/output:0")
17069     # check v->register
17070     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
17071     (check-strings-equal %eax "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register")
17072     # check v->type
17073     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
17074     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:0")  # Type-tree-is-atom
17075     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1")  # Type-tree-value
17076     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:2")  # Type-tree-right
17077 $test-function-header-with-multiple-args-and-outputs:out1:
17078     # outputs = lookup(outputs->next)
17079     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
17080     89/<- %edx 0/r32/eax
17081     # v = lookup(inouts->value)
17082     (lookup *edx *(edx+4))  # List-value List-value => eax
17083     89/<- %ebx 0/r32/eax
17084     # check v->name
17085     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
17086     (check-strings-equal %eax "_" "F - test-function-header-with-multiple-args-and-outputs/output:1")
17087     # check v->register
17088     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
17089     (check-strings-equal %eax "edx" "F - test-function-header-with-multiple-args-and-outputs/output:1/register")
17090     # check v->type
17091     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
17092     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:0")  # Type-tree-is-atom
17093     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1")  # Type-tree-value
17094     (check-ints-equal *(eax+0c) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:2")  # Type-tree-right
17095     # . epilogue
17096     89/<- %esp 5/r32/ebp
17097     5d/pop-to-ebp
17098     c3/return
17100 # format for variables with types
17101 #   x: int
17102 #   x: int,
17103 #   x/eax: int
17104 #   x/eax: int,
17105 # ignores at most one trailing comma
17106 # does not support other, non-register metadata
17107 # WARNING: modifies name
17108 parse-var-with-type:  # name: (addr slice), first-line: (addr stream byte), out: (addr handle var), fn-name: (addr array byte), err: (addr buffered-file), ed: (addr exit-descriptor)
17109     # pseudocode:
17110     #   var s: slice
17111     #   if (!slice-ends-with(name, ":"))
17112     #     abort
17113     #   --name->end to skip ':'
17114     #   next-token-from-slice(name->start, name->end, '/', s)
17115     #   new-var-from-slice(s, out)
17116     #   ## register
17117     #   next-token-from-slice(s->end, name->end, '/', s)
17118     #   if (!slice-empty?(s))
17119     #     out->register = slice-to-string(s)
17120     #   ## type
17121     #   var type: (handle type-tree) = parse-type(first-line)
17122     #   out->type = type
17123     #
17124     # . prologue
17125     55/push-ebp
17126     89/<- %ebp 4/r32/esp
17127     # . save registers
17128     50/push-eax
17129     51/push-ecx
17130     52/push-edx
17131     53/push-ebx
17132     56/push-esi
17133     57/push-edi
17134     # esi = name
17135     8b/-> *(ebp+8) 6/r32/esi
17136     # if (!slice-ends-with?(name, ":")) abort
17137     8b/-> *(esi+4) 1/r32/ecx  # Slice-end
17138     49/decrement-ecx
17139     8a/copy-byte *ecx 1/r32/CL
17140     81 4/subop/and %ecx 0xff/imm32
17141     81 7/subop/compare %ecx 0x3a/imm32/colon
17142     0f 85/jump-if-!= $parse-var-with-type:abort/disp32
17143     # --name->end to skip ':'
17144     ff 1/subop/decrement *(esi+4)
17145     # var s/ecx: slice
17146     68/push 0/imm32/end
17147     68/push 0/imm32/start
17148     89/<- %ecx 4/r32/esp
17149 $parse-var-with-type:parse-name:
17150     (next-token-from-slice *esi *(esi+4) 0x2f %ecx)  # Slice-start, Slice-end, '/'
17151 $parse-var-with-type:create-var:
17152     # new-var-from-slice(s, out)
17153     (new-var-from-slice Heap %ecx *(ebp+0x10))
17154     # save out->register
17155 $parse-var-with-type:save-register:
17156     # . var out-addr/edi: (addr var) = lookup(*out)
17157     8b/-> *(ebp+0x10) 7/r32/edi
17158     (lookup *edi *(edi+4))  # => eax
17159     89/<- %edi 0/r32/eax
17160     # . s = next-token(...)
17161     (next-token-from-slice *(ecx+4) *(esi+4) 0x2f %ecx)  # s->end, name->end, '/'
17162     # . if (!slice-empty?(s)) out->register = slice-to-string(s)
17163     {
17164 $parse-var-with-type:write-register:
17165       (slice-empty? %ecx)  # => eax
17166       3d/compare-eax-and 0/imm32/false
17167       75/jump-if-!= break/disp8
17168       # out->register = slice-to-string(s)
17169       8d/copy-address *(edi+0x18) 0/r32/eax  # Var-register
17170       (slice-to-string Heap %ecx %eax)
17171     }
17172 $parse-var-with-type:save-type:
17173     8d/copy-address *(edi+8) 0/r32/eax  # Var-type
17174     (parse-type Heap *(ebp+0xc) %eax *(ebp+0x18) *(ebp+0x1c))
17175 $parse-var-with-type:check-register:
17176     (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
17177     3d/compare-eax-and 0/imm32
17178     74/jump-if-= $parse-var-with-type:end/disp8
17179     (float-register? %eax)  # => eax
17180     {
17181       3d/compare-eax-and 0/imm32/false
17182       74/jump-if-= break/disp8
17183       # var is in a float register; ensure type is float
17184       (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
17185       (simple-mu-type? %eax 0xf)  # float => eax
17186       3d/compare-eax-and 0/imm32/false
17187       0f 84/jump-if-= $parse-var-with-type:error-non-float-in-floating-point-register/disp32
17188       eb/jump $parse-var-with-type:end/disp8
17189     }
17190     # var is not in a float register; ensure type is not float
17191     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
17192     (simple-mu-type? %eax 0xf)  # float => eax
17193     3d/compare-eax-and 0/imm32/false
17194     0f 85/jump-if-!= $parse-var-with-type:error-float-in-integer-register/disp32
17195 $parse-var-with-type:end:
17196     # . reclaim locals
17197     81 0/subop/add %esp 8/imm32
17198     # . restore registers
17199     5f/pop-to-edi
17200     5e/pop-to-esi
17201     5b/pop-to-ebx
17202     5a/pop-to-edx
17203     59/pop-to-ecx
17204     58/pop-to-eax
17205     # . epilogue
17206     89/<- %esp 5/r32/ebp
17207     5d/pop-to-ebp
17208     c3/return
17210 $parse-var-with-type:abort:
17211     # error("fn " fn ": var should have form 'name: type' in '" line "'\n")
17212     (write-buffered *(ebp+0x18) "fn ")
17213     (write-buffered *(ebp+0x18) *(ebp+0x14))
17214     (write-buffered *(ebp+0x18) ": var should have form 'name: type' in '")
17215     (flush *(ebp+0x18))
17216     (rewind-stream *(ebp+0xc))
17217     (write-stream-data *(ebp+0x18) *(ebp+0xc))
17218     (write-buffered *(ebp+0x18) "'\n")
17219     (flush *(ebp+0x18))
17220     (stop *(ebp+0x1c) 1)
17221     # never gets here
17223 $parse-var-with-type:error-float-in-integer-register:
17224     # error("fn " fn ": float var '" var "' should be in a floating-point register\n")
17225     (write-buffered *(ebp+0x18) "fn ")
17226     (write-buffered *(ebp+0x18) *(ebp+0x14))
17227     (write-buffered *(ebp+0x18) ": float var '")
17228     (lookup *edi *(edi+4))  # Var-name Var-name => eax
17229     (write-buffered *(ebp+0x18) %eax)
17230     (write-buffered *(ebp+0x18) "' should be in a floating-point register\n")
17231     (flush *(ebp+0x18))
17232     (stop *(ebp+0x1c) 1)
17233     # never gets here
17235 $parse-var-with-type:error-non-float-in-floating-point-register:
17236     # error("fn " fn ": non-float var '" var "' should be in an integer register\n")
17237     (write-buffered *(ebp+0x18) "fn ")
17238     (write-buffered *(ebp+0x18) *(ebp+0x14))
17239     (write-buffered *(ebp+0x18) ": non-float var '")
17240     (lookup *edi *(edi+4))  # Var-name Var-name => eax
17241     (write-buffered *(ebp+0x18) %eax)
17242     (write-buffered *(ebp+0x18) "' should be in an integer register\n")
17243     (flush *(ebp+0x18))
17244     (stop *(ebp+0x1c) 1)
17245     # never gets here
17247 float-register?:  # r: (addr array byte) -> result/eax: boolean
17248     # . prologue
17249     55/push-ebp
17250     89/<- %ebp 4/r32/esp
17251     #
17252     (get Mu-registers-unique *(ebp+8) 0xc "Mu-registers-unique")  # => eax
17253     81 7/subop/compare *eax 8/imm32/start-of-floating-point-registers
17254     0f 9d/set-if->= %al
17255     25/and-eax-with 0xff/imm32
17256 $float-register?:end:
17257     # . epilogue
17258     89/<- %esp 5/r32/ebp
17259     5d/pop-to-ebp
17260     c3/return
17262 parse-type:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle type-tree), err: (addr buffered-file), ed: (addr exit-descriptor)
17263     # pseudocode:
17264     #   var s: slice = next-mu-token(in)
17265     #   assert s != ""
17266     #   assert s != "->"
17267     #   assert s != "{"
17268     #   assert s != "}"
17269     #   if s == ")"
17270     #     return
17271     #   out = allocate(Type-tree)
17272     #   if s != "("
17273     #     HACK: if s is an int, parse and return it
17274     #     out->is-atom? = true
17275     #     if (s[0] == "_")
17276     #       out->value = type-parameter
17277     #       out->parameter-name = slice-to-string(ad, s)
17278     #     else
17279     #       out->value = pos-or-insert-slice(Type-id, s)
17280     #     return
17281     #   out->left = parse-type(ad, in)
17282     #   out->right = parse-type-tree(ad, in)
17283     #
17284     # . prologue
17285     55/push-ebp
17286     89/<- %ebp 4/r32/esp
17287     # . save registers
17288     50/push-eax
17289     51/push-ecx
17290     52/push-edx
17291     # clear out
17292     (zero-out *(ebp+0x10) *Handle-size)
17293     # var s/ecx: slice
17294     68/push 0/imm32
17295     68/push 0/imm32
17296     89/<- %ecx 4/r32/esp
17297     # s = next-mu-token(in)
17298     (next-mu-token *(ebp+0xc) %ecx)
17299 #?     (write-buffered Stderr "tok: ")
17300 #?     (write-slice-buffered Stderr %ecx)
17301 #?     (write-buffered Stderr "$\n")
17302 #?     (flush Stderr)
17303     # assert s != ""
17304     (slice-equal? %ecx "")  # => eax
17305     3d/compare-eax-and 0/imm32/false
17306     0f 85/jump-if-!= $parse-type:abort/disp32
17307     # assert s != "{"
17308     (slice-equal? %ecx "{")  # => eax
17309     3d/compare-eax-and 0/imm32/false
17310     0f 85/jump-if-!= $parse-type:abort/disp32
17311     # assert s != "}"
17312     (slice-equal? %ecx "}")  # => eax
17313     3d/compare-eax-and 0/imm32/false
17314     0f 85/jump-if-!= $parse-type:abort/disp32
17315     # assert s != "->"
17316     (slice-equal? %ecx "->")  # => eax
17317     3d/compare-eax-and 0/imm32/false
17318     0f 85/jump-if-!= $parse-type:abort/disp32
17319     # if (s == ")") return
17320     (slice-equal? %ecx ")")  # => eax
17321     3d/compare-eax-and 0/imm32/false
17322     0f 85/jump-if-!= $parse-type:end/disp32
17323     # out = new tree
17324     (allocate *(ebp+8) *Type-tree-size *(ebp+0x10))
17325     # var out-addr/edx: (addr type-tree) = lookup(*out)
17326     8b/-> *(ebp+0x10) 2/r32/edx
17327     (lookup *edx *(edx+4))  # => eax
17328     89/<- %edx 0/r32/eax
17329     {
17330       # if (s != "(") break
17331       (slice-equal? %ecx "(")  # => eax
17332       3d/compare-eax-and 0/imm32/false
17333       0f 85/jump-if-!= break/disp32
17334       # if s is a number, store it in the type's size field
17335       {
17336 $parse-type:check-for-int:
17337         # var tmp/eax: byte = *s->slice
17338         8b/-> *ecx 0/r32/eax
17339         8a/copy-byte *eax 0/r32/AL
17340         25/and-eax-with 0xff/imm32
17341         # TODO: raise an error on `var x: (array int a)`
17342         (decimal-digit? %eax)  # => eax
17343         3d/compare-eax-and 0/imm32/false
17344         74/jump-if-= break/disp8
17345 $parse-type:int:
17346         # strip out metadata
17347         (next-token-from-slice *ecx *(ecx+4) 0x2f %ecx)
17348         #
17349         (check-mu-hex-int %ecx *(ebp+0x14) *(ebp+0x18))
17350         (parse-hex-int-from-slice %ecx)  # => eax
17351         c7 0/subop/copy *(edx+4) 9/imm32/type-id-array-capacity  # Type-tree-value
17352         89/<- *(edx+8) 0/r32/eax  # Type-tree-value-size
17353         e9/jump $parse-type:end/disp32
17354       }
17355 $parse-type:atom:
17356       # out->is-atom? = true
17357       c7 0/subop/copy *edx 1/imm32/true  # Type-tree-is-atom
17358       {
17359 $parse-type:check-for-type-parameter:
17360         # var tmp/eax: byte = *s->slice
17361         8b/-> *ecx 0/r32/eax
17362         8a/copy-byte *eax 0/r32/AL
17363         25/and-eax-with 0xff/imm32
17364         # if (tmp != '_') break
17365         3d/compare-eax-and 0x5f/imm32/_
17366         75/jump-if-!= break/disp8
17367 $parse-type:type-parameter:
17368         # out->value = type-parameter
17369         c7 0/subop/copy *(edx+4) 0xa/imm32/type-parameter  # Type-tree-value
17370         # out->parameter-name = slice-to-string(ad, s)
17371         8d/copy-address *(edx+8) 0/r32/eax  # Type-tree-parameter-name
17372         (slice-to-string *(ebp+8) %ecx %eax)
17373         e9/jump $parse-type:end/disp32
17374       }
17375 $parse-type:non-type-parameter:
17376       # out->value = pos-or-insert-slice(Type-id, s)
17377       (pos-or-insert-slice Type-id %ecx)  # => eax
17378       89/<- *(edx+4) 0/r32/eax  # Type-tree-value
17379       e9/jump $parse-type:end/disp32
17380     }
17381 $parse-type:non-atom:
17382     # otherwise s == "("
17383     # out->left = parse-type(ad, in)
17384     8d/copy-address *(edx+4) 0/r32/eax  # Type-tree-left
17385     (parse-type *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
17386     # out->right = parse-type-tree(ad, in)
17387     8d/copy-address *(edx+0xc) 0/r32/eax  # Type-tree-right
17388     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
17389 $parse-type:end:
17390     # . reclaim locals
17391     81 0/subop/add %esp 8/imm32
17392     # . restore registers
17393     5a/pop-to-edx
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
17401 $parse-type:abort:
17402     # error("unexpected token when parsing type: '" s "'\n")
17403     (write-buffered *(ebp+0x14) "unexpected token when parsing type: '")
17404     (write-slice-buffered *(ebp+0x14) %ecx)
17405     (write-buffered *(ebp+0x14) "'\n")
17406     (flush *(ebp+0x14))
17407     (stop *(ebp+0x18) 1)
17408     # never gets here
17410 parse-type-tree:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle type-tree), err: (addr buffered-file), ed: (addr exit-descriptor)
17411     # pseudocode:
17412     #   var tmp: (handle type-tree) = parse-type(ad, in)
17413     #   if tmp == 0
17414     #     return 0
17415     #   out = allocate(Type-tree)
17416     #   out->left = tmp
17417     #   out->right = parse-type-tree(ad, in)
17418     #
17419     # . prologue
17420     55/push-ebp
17421     89/<- %ebp 4/r32/esp
17422     # . save registers
17423     50/push-eax
17424     51/push-ecx
17425     52/push-edx
17426     #
17427     (zero-out *(ebp+0x10) *Handle-size)
17428     # var tmp/ecx: (handle type-tree)
17429     68/push 0/imm32
17430     68/push 0/imm32
17431     89/<- %ecx 4/r32/esp
17432     # tmp = parse-type(ad, in)
17433     (parse-type *(ebp+8) *(ebp+0xc) %ecx *(ebp+0x14) *(ebp+0x18))
17434     # if (tmp == 0) return
17435     81 7/subop/compare *ecx 0/imm32
17436     74/jump-if-= $parse-type-tree:end/disp8
17437     # out = new tree
17438     (allocate *(ebp+8) *Type-tree-size *(ebp+0x10))
17439     # var out-addr/edx: (addr tree) = lookup(*out)
17440     8b/-> *(ebp+0x10) 2/r32/edx
17441     (lookup *edx *(edx+4))  # => eax
17442     89/<- %edx 0/r32/eax
17443     # out->left = tmp
17444     8b/-> *ecx 0/r32/eax
17445     89/<- *(edx+4) 0/r32/eax  # Type-tree-left
17446     8b/-> *(ecx+4) 0/r32/eax
17447     89/<- *(edx+8) 0/r32/eax  # Type-tree-left
17448     # out->right = parse-type-tree(ad, in)
17449     8d/copy-address *(edx+0xc) 0/r32/eax  # Type-tree-right
17450     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
17451 $parse-type-tree:end:
17452     # . reclaim locals
17453     81 0/subop/add %esp 8/imm32
17454     # . restore registers
17455     5a/pop-to-edx
17456     59/pop-to-ecx
17457     58/pop-to-eax
17458     # . epilogue
17459     89/<- %esp 5/r32/ebp
17460     5d/pop-to-ebp
17461     c3/return
17463 next-mu-token:  # in: (addr stream byte), out: (addr slice)
17464     # pseudocode:
17465     # start:
17466     #   skip-chars-matching-whitespace(in)
17467     #   if in->read >= in->write              # end of in
17468     #     out = {0, 0}
17469     #     return
17470     #   out->start = &in->data[in->read]
17471     #   var curr-byte/eax: byte = in->data[in->read]
17472     #   if curr->byte == ','                  # comment token
17473     #     ++in->read
17474     #     goto start
17475     #   if curr-byte == '#'                   # comment
17476     #     goto done                             # treat as eof
17477     #   if curr-byte == '"'                   # string literal
17478     #     skip-string(in)
17479     #     goto done                           # no metadata
17480     #   if curr-byte == '('
17481     #     ++in->read
17482     #     goto done
17483     #   if curr-byte == ')'
17484     #     ++in->read
17485     #     goto done
17486     #   # read a word
17487     #   while true
17488     #     if in->read >= in->write
17489     #       break
17490     #     curr-byte = in->data[in->read]
17491     #     if curr-byte == ' '
17492     #       break
17493     #     if curr-byte == '\r'
17494     #       break
17495     #     if curr-byte == '\n'
17496     #       break
17497     #     if curr-byte == '('
17498     #       break
17499     #     if curr-byte == ')'
17500     #       break
17501     #     if curr-byte == ','
17502     #       break
17503     #     ++in->read
17504     # done:
17505     #   out->end = &in->data[in->read]
17506     #
17507     # . prologue
17508     55/push-ebp
17509     89/<- %ebp 4/r32/esp
17510     # . save registers
17511     50/push-eax
17512     51/push-ecx
17513     56/push-esi
17514     57/push-edi
17515     # esi = in
17516     8b/-> *(ebp+8) 6/r32/esi
17517     # edi = out
17518     8b/-> *(ebp+0xc) 7/r32/edi
17519 $next-mu-token:start:
17520     (skip-chars-matching-whitespace %esi)
17521 $next-mu-token:check0:
17522     # if (in->read >= in->write) return out = {0, 0}
17523     # . ecx = in->read
17524     8b/-> *(esi+4) 1/r32/ecx
17525     # . if (ecx >= in->write) return out = {0, 0}
17526     3b/compare<- *esi 1/r32/ecx
17527     c7 0/subop/copy *edi 0/imm32
17528     c7 0/subop/copy *(edi+4) 0/imm32
17529     0f 8d/jump-if->= $next-mu-token:end/disp32
17530     # out->start = &in->data[in->read]
17531     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
17532     89/<- *edi 0/r32/eax
17533     # var curr-byte/eax: byte = in->data[in->read]
17534     31/xor-with %eax 0/r32/eax
17535     8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
17536     {
17537 $next-mu-token:check-for-comma:
17538       # if (curr-byte != ',') break
17539       3d/compare-eax-and 0x2c/imm32/comma
17540       75/jump-if-!= break/disp8
17541       # ++in->read
17542       ff 0/subop/increment *(esi+4)
17543       # restart
17544       e9/jump $next-mu-token:start/disp32
17545     }
17546     {
17547 $next-mu-token:check-for-comment:
17548       # if (curr-byte != '#') break
17549       3d/compare-eax-and 0x23/imm32/pound
17550       75/jump-if-!= break/disp8
17551       # return eof
17552       e9/jump $next-mu-token:done/disp32
17553     }
17554     {
17555 $next-mu-token:check-for-string-literal:
17556       # if (curr-byte != '"') break
17557       3d/compare-eax-and 0x22/imm32/dquote
17558       75/jump-if-!= break/disp8
17559       (skip-string %esi)
17560       # return
17561       e9/jump $next-mu-token:done/disp32
17562     }
17563     {
17564 $next-mu-token:check-for-open-paren:
17565       # if (curr-byte != '(') break
17566       3d/compare-eax-and 0x28/imm32/open-paren
17567       75/jump-if-!= break/disp8
17568       # ++in->read
17569       ff 0/subop/increment *(esi+4)
17570       # return
17571       e9/jump $next-mu-token:done/disp32
17572     }
17573     {
17574 $next-mu-token:check-for-close-paren:
17575       # if (curr-byte != ')') break
17576       3d/compare-eax-and 0x29/imm32/close-paren
17577       75/jump-if-!= break/disp8
17578       # ++in->read
17579       ff 0/subop/increment *(esi+4)
17580       # return
17581       e9/jump $next-mu-token:done/disp32
17582     }
17583     {
17584 $next-mu-token:regular-word-without-metadata:
17585       # if (in->read >= in->write) break
17586       # . ecx = in->read
17587       8b/-> *(esi+4) 1/r32/ecx
17588       # . if (ecx >= in->write) break
17589       3b/compare<- *esi 1/r32/ecx
17590       7d/jump-if->= break/disp8
17591       # var c/eax: byte = in->data[in->read]
17592       31/xor-with %eax 0/r32/eax
17593       8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
17594       # if (c == ' ') break
17595       3d/compare-eax-and 0x20/imm32/space
17596       74/jump-if-= break/disp8
17597       # if (c == '\r') break
17598       3d/compare-eax-and 0xd/imm32/carriage-return
17599       74/jump-if-= break/disp8
17600       # if (c == '\n') break
17601       3d/compare-eax-and 0xa/imm32/newline
17602       74/jump-if-= break/disp8
17603       # if (c == '(') break
17604       3d/compare-eax-and 0x28/imm32/open-paren
17605       0f 84/jump-if-= break/disp32
17606       # if (c == ')') break
17607       3d/compare-eax-and 0x29/imm32/close-paren
17608       0f 84/jump-if-= break/disp32
17609       # if (c == ',') break
17610       3d/compare-eax-and 0x2c/imm32/comma
17611       0f 84/jump-if-= break/disp32
17612       # ++in->read
17613       ff 0/subop/increment *(esi+4)
17614       #
17615       e9/jump loop/disp32
17616     }
17617 $next-mu-token:done:
17618     # out->end = &in->data[in->read]
17619     8b/-> *(esi+4) 1/r32/ecx
17620     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
17621     89/<- *(edi+4) 0/r32/eax
17622 $next-mu-token:end:
17623     # . restore registers
17624     5f/pop-to-edi
17625     5e/pop-to-esi
17626     59/pop-to-ecx
17627     58/pop-to-eax
17628     # . epilogue
17629     89/<- %esp 5/r32/ebp
17630     5d/pop-to-ebp
17631     c3/return
17633 pos-or-insert-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
17634     # . prologue
17635     55/push-ebp
17636     89/<- %ebp 4/r32/esp
17637     # if (pos-slice(arr, s) != -1) return it
17638     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
17639     3d/compare-eax-and -1/imm32
17640     75/jump-if-!= $pos-or-insert-slice:end/disp8
17641 $pos-or-insert-slice:insert:
17642     # var s2/eax: (handle array byte)
17643     68/push 0/imm32
17644     68/push 0/imm32
17645     89/<- %eax 4/r32/esp
17646     (slice-to-string Heap *(ebp+0xc) %eax)
17647     # throw away alloc-id
17648     (lookup *eax *(eax+4))  # => eax
17649     (write-int *(ebp+8) %eax)
17650     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
17651 $pos-or-insert-slice:end:
17652     # . reclaim locals
17653     81 0/subop/add %esp 8/imm32
17654     # . epilogue
17655     89/<- %esp 5/r32/ebp
17656     5d/pop-to-ebp
17657     c3/return
17659 # return the index in an array of strings matching 's', -1 if not found
17660 # index is denominated in elements, not bytes
17661 pos-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
17662     # . prologue
17663     55/push-ebp
17664     89/<- %ebp 4/r32/esp
17665     # . save registers
17666     51/push-ecx
17667     52/push-edx
17668     53/push-ebx
17669     56/push-esi
17670 #?     (write-buffered Stderr "pos-slice: ")
17671 #?     (write-slice-buffered Stderr *(ebp+0xc))
17672 #?     (write-buffered Stderr "\n")
17673 #?     (flush Stderr)
17674     # esi = arr
17675     8b/-> *(ebp+8) 6/r32/esi
17676     # var index/ecx: int = 0
17677     b9/copy-to-ecx 0/imm32
17678     # var curr/edx: (addr (addr array byte)) = arr->data
17679     8d/copy-address *(esi+0xc) 2/r32/edx
17680     # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write]
17681     8b/-> *esi 3/r32/ebx
17682     8d/copy-address *(esi+ebx+0xc) 3/r32/ebx
17683     {
17684 #?       (write-buffered Stderr "  ")
17685 #?       (write-int32-hex-buffered Stderr %ecx)
17686 #?       (write-buffered Stderr "\n")
17687 #?       (flush Stderr)
17688       # if (curr >= max) return -1
17689       39/compare %edx 3/r32/ebx
17690       b8/copy-to-eax -1/imm32
17691       73/jump-if-addr>= $pos-slice:end/disp8
17692       # if (slice-equal?(s, *curr)) break
17693       (slice-equal? *(ebp+0xc) *edx)  # => eax
17694       3d/compare-eax-and 0/imm32/false
17695       75/jump-if-!= break/disp8
17696       # ++index
17697       41/increment-ecx
17698       # curr += 4
17699       81 0/subop/add %edx 4/imm32
17700       #
17701       eb/jump loop/disp8
17702     }
17703     # return index
17704     89/<- %eax 1/r32/ecx
17705 $pos-slice:end:
17706 #?     (write-buffered Stderr "=> ")
17707 #?     (write-int32-hex-buffered Stderr %eax)
17708 #?     (write-buffered Stderr "\n")
17709     # . restore registers
17710     5e/pop-to-esi
17711     5b/pop-to-ebx
17712     5a/pop-to-edx
17713     59/pop-to-ecx
17714     # . epilogue
17715     89/<- %esp 5/r32/ebp
17716     5d/pop-to-ebp
17717     c3/return
17719 test-parse-var-with-type:
17720     # . prologue
17721     55/push-ebp
17722     89/<- %ebp 4/r32/esp
17723     # setup
17724     8b/-> *Primitive-type-ids 0/r32/eax
17725     89/<- *Type-id 0/r32/eax  # stream-write
17726     # (eax..ecx) = "x:"
17727     b8/copy-to-eax "x:"/imm32
17728     8b/-> *eax 1/r32/ecx
17729     8d/copy-address *(eax+ecx+4) 1/r32/ecx
17730     05/add-to-eax 4/imm32
17731     # var slice/ecx: slice = {eax, ecx}
17732     51/push-ecx
17733     50/push-eax
17734     89/<- %ecx 4/r32/esp
17735     # _test-input-stream contains "int"
17736     (clear-stream _test-input-stream)
17737     (write _test-input-stream "int")
17738     # var v/edx: (handle var)
17739     68/push 0/imm32
17740     68/push 0/imm32
17741     89/<- %edx 4/r32/esp
17742     #
17743     (parse-var-with-type %ecx _test-input-stream %edx 0 Stderr 0)
17744     # var v-addr/edx: (addr var) = lookup(v)
17745     (lookup *edx *(edx+4))  # => eax
17746     89/<- %edx 0/r32/eax
17747     # check v-addr->name
17748     (lookup *edx *(edx+4))  # Var-name Var-name => eax
17749     (check-strings-equal %eax "x" "F - test-parse-var-with-type/name")
17750     # check v-addr->type
17751     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
17752     (check-ints-equal *eax 1 "F - test-parse-var-with-type/type:0")  # Type-tree-is-atom
17753     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type/type:1")  # Type-tree-value
17754     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type/type:2")  # Type-tree-right
17755     # . epilogue
17756     89/<- %esp 5/r32/ebp
17757     5d/pop-to-ebp
17758     c3/return
17760 test-parse-var-with-type-and-register:
17761     # . prologue
17762     55/push-ebp
17763     89/<- %ebp 4/r32/esp
17764     # setup
17765     8b/-> *Primitive-type-ids 0/r32/eax
17766     89/<- *Type-id 0/r32/eax  # stream-write
17767     # (eax..ecx) = "x/eax:"
17768     b8/copy-to-eax "x/eax:"/imm32
17769     8b/-> *eax 1/r32/ecx
17770     8d/copy-address *(eax+ecx+4) 1/r32/ecx
17771     05/add-to-eax 4/imm32
17772     # var slice/ecx: slice = {eax, ecx}
17773     51/push-ecx
17774     50/push-eax
17775     89/<- %ecx 4/r32/esp
17776     # _test-input-stream contains "int"
17777     (clear-stream _test-input-stream)
17778     (write _test-input-stream "int")
17779     # var v/edx: (handle var)
17780     68/push 0/imm32
17781     68/push 0/imm32
17782     89/<- %edx 4/r32/esp
17783     #
17784     (parse-var-with-type %ecx _test-input-stream %edx 0 Stderr 0)
17785     # var v-addr/edx: (addr var) = lookup(v)
17786     (lookup *edx *(edx+4))  # => eax
17787     89/<- %edx 0/r32/eax
17788     # check v-addr->name
17789     (lookup *edx *(edx+4))  # Var-name Var-name => eax
17790     (check-strings-equal %eax "x" "F - test-parse-var-with-type-and-register/name")
17791     # check v-addr->register
17792     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
17793     (check-strings-equal %eax "eax" "F - test-parse-var-with-type-and-register/register")
17794     # check v-addr->type
17795     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
17796     (check-ints-equal *eax 1 "F - test-parse-var-with-type-and-register/type:0")  # Type-tree-is-atom
17797     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type-and-register/type:1")  # Type-tree-left
17798     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type-and-register/type:2")  # Type-tree-right
17799     # . epilogue
17800     89/<- %esp 5/r32/ebp
17801     5d/pop-to-ebp
17802     c3/return
17804 test-parse-var-with-trailing-characters:
17805     # . prologue
17806     55/push-ebp
17807     89/<- %ebp 4/r32/esp
17808     # setup
17809     8b/-> *Primitive-type-ids 0/r32/eax
17810     89/<- *Type-id 0/r32/eax  # stream-write
17811     # (eax..ecx) = "x:"
17812     b8/copy-to-eax "x:"/imm32
17813     8b/-> *eax 1/r32/ecx
17814     8d/copy-address *(eax+ecx+4) 1/r32/ecx
17815     05/add-to-eax 4/imm32
17816     # var slice/ecx: slice = {eax, ecx}
17817     51/push-ecx
17818     50/push-eax
17819     89/<- %ecx 4/r32/esp
17820     # _test-input-stream contains "int,"
17821     (clear-stream _test-input-stream)
17822     (write _test-input-stream "int,")
17823     # var v/edx: (handle var)
17824     68/push 0/imm32
17825     68/push 0/imm32
17826     89/<- %edx 4/r32/esp
17827     #
17828     (parse-var-with-type %ecx _test-input-stream %edx 0 Stderr 0)
17829     # var v-addr/edx: (addr var) = lookup(v)
17830     (lookup *edx *(edx+4))  # => eax
17831     89/<- %edx 0/r32/eax
17832     # check v-addr->name
17833     (lookup *edx *(edx+4))  # Var-name Var-name => eax
17834     (check-strings-equal %eax "x" "F - test-parse-var-with-trailing-characters/name")
17835     # check v-addr->register
17836     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-trailing-characters/register")  # Var-register
17837     # check v-addr->type
17838     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
17839     (check-ints-equal *eax 1 "F - test-parse-var-with-trailing-characters/type:0")  # Type-tree-is-atom
17840     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-trailing-characters/type:1")  # Type-tree-left
17841     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-trailing-characters/type:1")  # Type-tree-right
17842     # . epilogue
17843     89/<- %esp 5/r32/ebp
17844     5d/pop-to-ebp
17845     c3/return
17847 test-parse-var-with-register-and-trailing-characters:
17848     # . prologue
17849     55/push-ebp
17850     89/<- %ebp 4/r32/esp
17851     # setup
17852     8b/-> *Primitive-type-ids 0/r32/eax
17853     89/<- *Type-id 0/r32/eax  # stream-write
17854     # (eax..ecx) = "x/eax:"
17855     b8/copy-to-eax "x/eax:"/imm32
17856     8b/-> *eax 1/r32/ecx
17857     8d/copy-address *(eax+ecx+4) 1/r32/ecx
17858     05/add-to-eax 4/imm32
17859     # var slice/ecx: slice = {eax, ecx}
17860     51/push-ecx
17861     50/push-eax
17862     89/<- %ecx 4/r32/esp
17863     # _test-input-stream contains "int,"
17864     (clear-stream _test-input-stream)
17865     (write _test-input-stream "int,")
17866     # var v/edx: (handle var)
17867     68/push 0/imm32
17868     68/push 0/imm32
17869     89/<- %edx 4/r32/esp
17870     #
17871     (parse-var-with-type %ecx _test-input-stream %edx 0 Stderr 0)
17872     # var v-addr/edx: (addr var) = lookup(v)
17873     (lookup *edx *(edx+4))  # => eax
17874     89/<- %edx 0/r32/eax
17875     # check v-addr->name
17876     (lookup *edx *(edx+4))  # Var-name Var-name => eax
17877     (check-strings-equal %eax "x" "F - test-parse-var-with-register-and-trailing-characters/name")
17878     # check v-addr->register
17879     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
17880     (check-strings-equal %eax "eax" "F - test-parse-var-with-register-and-trailing-characters/register")
17881     # check v-addr->type
17882     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
17883     (check-ints-equal *eax 1 "F - test-parse-var-with-register-and-trailing-characters/type:0")  # Type-tree-is-atom
17884     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-register-and-trailing-characters/type:1")  # Type-tree-left
17885     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-register-and-trailing-characters/type:2")  # Type-tree-right
17886     # . epilogue
17887     89/<- %esp 5/r32/ebp
17888     5d/pop-to-ebp
17889     c3/return
17891 test-parse-var-with-compound-type:
17892     # . prologue
17893     55/push-ebp
17894     89/<- %ebp 4/r32/esp
17895     # setup
17896     8b/-> *Primitive-type-ids 0/r32/eax
17897     89/<- *Type-id 0/r32/eax  # stream-write
17898     # (eax..ecx) = "x:"
17899     b8/copy-to-eax "x:"/imm32
17900     8b/-> *eax 1/r32/ecx
17901     8d/copy-address *(eax+ecx+4) 1/r32/ecx
17902     05/add-to-eax 4/imm32
17903     # var slice/ecx: slice = {eax, ecx}
17904     51/push-ecx
17905     50/push-eax
17906     89/<- %ecx 4/r32/esp
17907     # _test-input-stream contains "(addr int)"
17908     (clear-stream _test-input-stream)
17909     (write _test-input-stream "(addr int)")
17910     # var v/edx: (handle var)
17911     68/push 0/imm32
17912     68/push 0/imm32
17913     89/<- %edx 4/r32/esp
17914     #
17915     (parse-var-with-type %ecx _test-input-stream %edx 0 Stderr 0)
17916     # var v-addr/edx: (addr var) = lookup(v)
17917     (lookup *edx *(edx+4))  # => eax
17918     89/<- %edx 0/r32/eax
17919     # check v-addr->name
17920     (lookup *edx *(edx+4))  # Var-name Var-name => eax
17921     (check-strings-equal %eax "x" "F - test-parse-var-with-compound-type/name")
17922     # check v-addr->register
17923     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-compound-type/register")  # Var-register
17924     # - check v-addr->type
17925     # var type/edx: (addr type-tree) = var->type
17926     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
17927     89/<- %edx 0/r32/eax
17928     # type is a non-atom
17929     (check-ints-equal *edx 0 "F - test-parse-var-with-compound-type/type:0")  # Type-tree-is-atom
17930     # type->left == atom(addr)
17931     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
17932     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:1")  # Type-tree-is-atom
17933     (check-ints-equal *(eax+4) 2 "F - test-parse-var-with-compound-type/type:2")  # Type-tree-value
17934     # type->right->left == atom(int)
17935     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
17936     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
17937     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:3")  # Type-tree-is-atom
17938     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-compound-type/type:4")  # Type-tree-value
17939     # type->right->right == null
17940     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-compound-type/type:5")  # Type-tree-right
17941     # . epilogue
17942     89/<- %esp 5/r32/ebp
17943     5d/pop-to-ebp
17944     c3/return
17946 # identifier starts with a letter or '$' or '_'
17947 # no constraints at the moment on later letters
17948 # all we really want to do so far is exclude '{', '}' and '->'
17949 identifier?:  # in: (addr slice) -> result/eax: boolean
17950     # . prologue
17951     55/push-ebp
17952     89/<- %ebp 4/r32/esp
17953     # if (slice-empty?(in)) return false
17954     (slice-empty? *(ebp+8))  # => eax
17955     3d/compare-eax-and 0/imm32/false
17956     75/jump-if-!= $identifier?:false/disp8
17957     # var c/eax: byte = *in->start
17958     8b/-> *(ebp+8) 0/r32/eax
17959     8b/-> *eax 0/r32/eax
17960     8a/copy-byte *eax 0/r32/AL
17961     25/and-eax-with 0xff/imm32
17962     # if (c == '$') return true
17963     3d/compare-eax-and 0x24/imm32/$
17964     74/jump-if-= $identifier?:true/disp8
17965     # if (c == '_') return true
17966     3d/compare-eax-and 0x5f/imm32/_
17967     74/jump-if-= $identifier?:true/disp8
17968     # drop case
17969     25/and-eax-with 0x5f/imm32
17970     # if (c < 'A') return false
17971     3d/compare-eax-and 0x41/imm32/A
17972     7c/jump-if-< $identifier?:false/disp8
17973     # if (c > 'Z') return false
17974     3d/compare-eax-and 0x5a/imm32/Z
17975     7f/jump-if-> $identifier?:false/disp8
17976     # otherwise return true
17977 $identifier?:true:
17978     b8/copy-to-eax 1/imm32/true
17979     eb/jump $identifier?:end/disp8
17980 $identifier?:false:
17981     b8/copy-to-eax 0/imm32/false
17982 $identifier?:end:
17983     # . epilogue
17984     89/<- %esp 5/r32/ebp
17985     5d/pop-to-ebp
17986     c3/return
17988 test-is-identifier-dollar:
17989     # . prologue
17990     55/push-ebp
17991     89/<- %ebp 4/r32/esp
17992     # (eax..ecx) = "$a"
17993     b8/copy-to-eax "$a"/imm32
17994     8b/-> *eax 1/r32/ecx
17995     8d/copy-address *(eax+ecx+4) 1/r32/ecx
17996     05/add-to-eax 4/imm32
17997     # var slice/ecx: slice = {eax, ecx}
17998     51/push-ecx
17999     50/push-eax
18000     89/<- %ecx 4/r32/esp
18001     #
18002     (identifier? %ecx)
18003     (check-ints-equal %eax 1 "F - test-is-identifier-dollar")
18004     # . epilogue
18005     89/<- %esp 5/r32/ebp
18006     5d/pop-to-ebp
18007     c3/return
18009 test-is-identifier-underscore:
18010     # . prologue
18011     55/push-ebp
18012     89/<- %ebp 4/r32/esp
18013     # (eax..ecx) = "_a"
18014     b8/copy-to-eax "_a"/imm32
18015     8b/-> *eax 1/r32/ecx
18016     8d/copy-address *(eax+ecx+4) 1/r32/ecx
18017     05/add-to-eax 4/imm32
18018     # var slice/ecx: slice = {eax, ecx}
18019     51/push-ecx
18020     50/push-eax
18021     89/<- %ecx 4/r32/esp
18022     #
18023     (identifier? %ecx)
18024     (check-ints-equal %eax 1 "F - test-is-identifier-underscore")
18025     # . epilogue
18026     89/<- %esp 5/r32/ebp
18027     5d/pop-to-ebp
18028     c3/return
18030 test-is-identifier-a:
18031     # . prologue
18032     55/push-ebp
18033     89/<- %ebp 4/r32/esp
18034     # (eax..ecx) = "a$"
18035     b8/copy-to-eax "a$"/imm32
18036     8b/-> *eax 1/r32/ecx
18037     8d/copy-address *(eax+ecx+4) 1/r32/ecx
18038     05/add-to-eax 4/imm32
18039     # var slice/ecx: slice = {eax, ecx}
18040     51/push-ecx
18041     50/push-eax
18042     89/<- %ecx 4/r32/esp
18043     #
18044     (identifier? %ecx)
18045     (check-ints-equal %eax 1 "F - test-is-identifier-a")
18046     # . epilogue
18047     89/<- %esp 5/r32/ebp
18048     5d/pop-to-ebp
18049     c3/return
18051 test-is-identifier-z:
18052     # . prologue
18053     55/push-ebp
18054     89/<- %ebp 4/r32/esp
18055     # (eax..ecx) = "z$"
18056     b8/copy-to-eax "z$"/imm32
18057     8b/-> *eax 1/r32/ecx
18058     8d/copy-address *(eax+ecx+4) 1/r32/ecx
18059     05/add-to-eax 4/imm32
18060     # var slice/ecx: slice = {eax, ecx}
18061     51/push-ecx
18062     50/push-eax
18063     89/<- %ecx 4/r32/esp
18064     #
18065     (identifier? %ecx)
18066     (check-ints-equal %eax 1 "F - test-is-identifier-z")
18067     # . epilogue
18068     89/<- %esp 5/r32/ebp
18069     5d/pop-to-ebp
18070     c3/return
18072 test-is-identifier-A:
18073     # . prologue
18074     55/push-ebp
18075     89/<- %ebp 4/r32/esp
18076     # (eax..ecx) = "A$"
18077     b8/copy-to-eax "A$"/imm32
18078     8b/-> *eax 1/r32/ecx
18079     8d/copy-address *(eax+ecx+4) 1/r32/ecx
18080     05/add-to-eax 4/imm32
18081     # var slice/ecx: slice = {eax, ecx}
18082     51/push-ecx
18083     50/push-eax
18084     89/<- %ecx 4/r32/esp
18085     #
18086     (identifier? %ecx)
18087     (check-ints-equal %eax 1 "F - test-is-identifier-A")
18088     # . epilogue
18089     89/<- %esp 5/r32/ebp
18090     5d/pop-to-ebp
18091     c3/return
18093 test-is-identifier-Z:
18094     # . prologue
18095     55/push-ebp
18096     89/<- %ebp 4/r32/esp
18097     # (eax..ecx) = "Z$"
18098     b8/copy-to-eax "Z$"/imm32
18099     8b/-> *eax 1/r32/ecx
18100     8d/copy-address *(eax+ecx+4) 1/r32/ecx
18101     05/add-to-eax 4/imm32
18102     # var slice/ecx: slice = {eax, ecx}
18103     51/push-ecx
18104     50/push-eax
18105     89/<- %ecx 4/r32/esp
18106     #
18107     (identifier? %ecx)
18108     (check-ints-equal %eax 1 "F - test-is-identifier-Z")
18109     # . epilogue
18110     89/<- %esp 5/r32/ebp
18111     5d/pop-to-ebp
18112     c3/return
18114 test-is-identifier-at:
18115     # character before 'A' is invalid
18116     # . prologue
18117     55/push-ebp
18118     89/<- %ebp 4/r32/esp
18119     # (eax..ecx) = "@a"
18120     b8/copy-to-eax "@a"/imm32
18121     8b/-> *eax 1/r32/ecx
18122     8d/copy-address *(eax+ecx+4) 1/r32/ecx
18123     05/add-to-eax 4/imm32
18124     # var slice/ecx: slice = {eax, ecx}
18125     51/push-ecx
18126     50/push-eax
18127     89/<- %ecx 4/r32/esp
18128     #
18129     (identifier? %ecx)
18130     (check-ints-equal %eax 0 "F - test-is-identifier-@")
18131     # . epilogue
18132     89/<- %esp 5/r32/ebp
18133     5d/pop-to-ebp
18134     c3/return
18136 test-is-identifier-square-bracket:
18137     # character after 'Z' is invalid
18138     # . prologue
18139     55/push-ebp
18140     89/<- %ebp 4/r32/esp
18141     # (eax..ecx) = "[a"
18142     b8/copy-to-eax "[a"/imm32
18143     8b/-> *eax 1/r32/ecx
18144     8d/copy-address *(eax+ecx+4) 1/r32/ecx
18145     05/add-to-eax 4/imm32
18146     # var slice/ecx: slice = {eax, ecx}
18147     51/push-ecx
18148     50/push-eax
18149     89/<- %ecx 4/r32/esp
18150     #
18151     (identifier? %ecx)
18152     (check-ints-equal %eax 0 "F - test-is-identifier-@")
18153     # . epilogue
18154     89/<- %esp 5/r32/ebp
18155     5d/pop-to-ebp
18156     c3/return
18158 test-is-identifier-backtick:
18159     # character before 'a' is invalid
18160     # . prologue
18161     55/push-ebp
18162     89/<- %ebp 4/r32/esp
18163     # (eax..ecx) = "`a"
18164     b8/copy-to-eax "`a"/imm32
18165     8b/-> *eax 1/r32/ecx
18166     8d/copy-address *(eax+ecx+4) 1/r32/ecx
18167     05/add-to-eax 4/imm32
18168     # var slice/ecx: slice = {eax, ecx}
18169     51/push-ecx
18170     50/push-eax
18171     89/<- %ecx 4/r32/esp
18172     #
18173     (identifier? %ecx)
18174     (check-ints-equal %eax 0 "F - test-is-identifier-backtick")
18175     # . epilogue
18176     89/<- %esp 5/r32/ebp
18177     5d/pop-to-ebp
18178     c3/return
18180 test-is-identifier-curly-brace-open:
18181     # character after 'z' is invalid; also used for blocks
18182     # . prologue
18183     55/push-ebp
18184     89/<- %ebp 4/r32/esp
18185     # (eax..ecx) = "{a"
18186     b8/copy-to-eax "{a"/imm32
18187     8b/-> *eax 1/r32/ecx
18188     8d/copy-address *(eax+ecx+4) 1/r32/ecx
18189     05/add-to-eax 4/imm32
18190     # var slice/ecx: slice = {eax, ecx}
18191     51/push-ecx
18192     50/push-eax
18193     89/<- %ecx 4/r32/esp
18194     #
18195     (identifier? %ecx)
18196     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open")
18197     # . epilogue
18198     89/<- %esp 5/r32/ebp
18199     5d/pop-to-ebp
18200     c3/return
18202 test-is-identifier-curly-brace-close:
18203     # . prologue
18204     55/push-ebp
18205     89/<- %ebp 4/r32/esp
18206     # (eax..ecx) = "}a"
18207     b8/copy-to-eax "}a"/imm32
18208     8b/-> *eax 1/r32/ecx
18209     8d/copy-address *(eax+ecx+4) 1/r32/ecx
18210     05/add-to-eax 4/imm32
18211     # var slice/ecx: slice = {eax, ecx}
18212     51/push-ecx
18213     50/push-eax
18214     89/<- %ecx 4/r32/esp
18215     #
18216     (identifier? %ecx)
18217     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close")
18218     # . epilogue
18219     89/<- %esp 5/r32/ebp
18220     5d/pop-to-ebp
18221     c3/return
18223 test-is-identifier-hyphen:
18224     # disallow leading '-' since '->' has special meaning
18225     # . prologue
18226     55/push-ebp
18227     89/<- %ebp 4/r32/esp
18228     # (eax..ecx) = "-a"
18229     b8/copy-to-eax "-a"/imm32
18230     8b/-> *eax 1/r32/ecx
18231     8d/copy-address *(eax+ecx+4) 1/r32/ecx
18232     05/add-to-eax 4/imm32
18233     # var slice/ecx: slice = {eax, ecx}
18234     51/push-ecx
18235     50/push-eax
18236     89/<- %ecx 4/r32/esp
18237     #
18238     (identifier? %ecx)
18239     (check-ints-equal %eax 0 "F - test-is-identifier-hyphen")
18240     # . epilogue
18241     89/<- %esp 5/r32/ebp
18242     5d/pop-to-ebp
18243     c3/return
18245 populate-mu-function-body:  # in: (addr buffered-file), out: (addr function), vars: (addr stack live-var), err: (addr buffered-file), ed: (addr exit-descriptor)
18246     # . prologue
18247     55/push-ebp
18248     89/<- %ebp 4/r32/esp
18249     # . save registers
18250     50/push-eax
18251     56/push-esi
18252     57/push-edi
18253     # esi = in
18254     8b/-> *(ebp+8) 6/r32/esi
18255     # edi = out
18256     8b/-> *(ebp+0xc) 7/r32/edi
18257     # initialize some global state
18258     c7 0/subop/copy *Curr-block-depth 1/imm32
18259     # parse-mu-block(in, vars, out, out->body)
18260     8d/copy-address *(edi+0x18) 0/r32/eax  # Function-body
18261     (parse-mu-block %esi *(ebp+0x10) %edi %eax *(ebp+0x14) *(ebp+0x18))
18262 $populate-mu-function-body:end:
18263     # . restore registers
18264     5f/pop-to-edi
18265     5e/pop-to-esi
18266     58/pop-to-eax
18267     # . epilogue
18268     89/<- %esp 5/r32/ebp
18269     5d/pop-to-ebp
18270     c3/return
18272 # parses a block, assuming that the leading '{' has already been read by the caller
18273 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)
18274     # pseudocode:
18275     #   var line: (stream byte 512)
18276     #   var word-slice: slice
18277     #   allocate(Heap, Stmt-size, out)
18278     #   var out-addr: (addr block) = lookup(*out)
18279     #   out-addr->tag = 0/block
18280     #   out-addr->var = some unique name
18281     #   push(vars, {out-addr->var, false})
18282     #   while true                                  # line loop
18283     #     clear-stream(line)
18284     #     read-line-buffered(in, line)
18285     #     if (line->write == 0) break               # end of file
18286     #     word-slice = next-mu-token(line)
18287     #     if slice-empty?(word-slice)               # end of line
18288     #       continue
18289     #     else if slice-starts-with?(word-slice, "#")
18290     #       continue
18291     #     else if slice-equal?(word-slice, "{")
18292     #       assert(no-tokens-in(line))
18293     #       block = parse-mu-block(in, vars, fn)
18294     #       append-to-block(out-addr, block)
18295     #     else if slice-equal?(word-slice, "}")
18296     #       break
18297     #     else if slice-ends-with?(word-slice, ":")
18298     #       if !slice-equal?(next-mu-token(line), "{")
18299     #         abort
18300     #       --word-slice->end to skip ':'
18301     #       named-block = parse-mu-named-block(word-slice, in, vars, fn)
18302     #       append-to-block(out-addr, named-block)
18303     #     else if slice-equal?(word-slice, "var")
18304     #       var-def = parse-mu-var-def(line, vars, fn)
18305     #       append-to-block(out-addr, var-def)
18306     #     else
18307     #       stmt = parse-mu-stmt(line, vars, fn)
18308     #       append-to-block(out-addr, stmt)
18309     #   pop(vars)
18310     #
18311     # . prologue
18312     55/push-ebp
18313     89/<- %ebp 4/r32/esp
18314     # . save registers
18315     50/push-eax
18316     51/push-ecx
18317     52/push-edx
18318     53/push-ebx
18319     57/push-edi
18320     # var line/ecx: (stream byte 512)
18321     81 5/subop/subtract %esp 0x200/imm32
18322     68/push 0x200/imm32/size
18323     68/push 0/imm32/read
18324     68/push 0/imm32/write
18325     89/<- %ecx 4/r32/esp
18326     # var word-slice/edx: slice
18327     68/push 0/imm32/end
18328     68/push 0/imm32/start
18329     89/<- %edx 4/r32/esp
18330     # allocate into out
18331     (allocate Heap *Stmt-size *(ebp+0x14))
18332     # var out-addr/edi: (addr block) = lookup(*out)
18333     8b/-> *(ebp+0x14) 7/r32/edi
18334     (lookup *edi *(edi+4))  # => eax
18335     89/<- %edi 0/r32/eax
18336     # out-addr->tag is 0 (block) by default
18337     # set out-addr->var
18338     8d/copy-address *(edi+0xc) 0/r32/eax  # Block-var
18339     (new-block-name *(ebp+0x10) %eax)
18340     # push(vars, out-addr->var)
18341     (push *(ebp+0xc) *(edi+0xc))  # Block-var
18342     (push *(ebp+0xc) *(edi+0x10))  # Block-var
18343     (push *(ebp+0xc) 0)  # false
18344     # increment *Curr-block-depth
18345     ff 0/subop/increment *Curr-block-depth
18346     {
18347 $parse-mu-block:line-loop:
18348       # line = read-line-buffered(in)
18349       (clear-stream %ecx)
18350       (read-line-buffered *(ebp+8) %ecx)
18351 #?       (write-buffered Stderr "line: ")
18352 #?       (write-stream-data Stderr %ecx)
18353 #? #?       (write-buffered Stderr Newline)  # line has its own newline
18354 #?       (flush Stderr)
18355 #?       (rewind-stream %ecx)
18356       # if (line->write == 0) break
18357       81 7/subop/compare *ecx 0/imm32
18358       0f 84/jump-if-= break/disp32
18359 #?       (write-buffered Stderr "vars:\n")
18360 #?       (dump-vars *(ebp+0xc))
18361       # word-slice = next-mu-token(line)
18362       (next-mu-token %ecx %edx)
18363 #?       (write-buffered Stderr "word: ")
18364 #?       (write-slice-buffered Stderr %edx)
18365 #?       (write-buffered Stderr Newline)
18366 #?       (flush Stderr)
18367       # if slice-empty?(word-slice) continue
18368       (slice-empty? %edx)
18369       3d/compare-eax-and 0/imm32/false
18370       0f 85/jump-if-!= loop/disp32
18371       # if (slice-starts-with?(word-slice, '#') continue
18372       # . eax = *word-slice->start
18373       8b/-> *edx 0/r32/eax
18374       8a/copy-byte *eax 0/r32/AL
18375       25/and-eax-with 0xff/imm32
18376       # . if (eax == '#') continue
18377       3d/compare-eax-and 0x23/imm32/hash
18378       0f 84/jump-if-= loop/disp32
18379       # if slice-equal?(word-slice, "{")
18380       {
18381 $parse-mu-block:check-for-block:
18382         (slice-equal? %edx "{")
18383         3d/compare-eax-and 0/imm32/false
18384         74/jump-if-= break/disp8
18385         (check-no-tokens-left %ecx)
18386         # parse new block and append
18387         # . var tmp/eax: (handle block)
18388         68/push 0/imm32
18389         68/push 0/imm32
18390         89/<- %eax 4/r32/esp
18391         # .
18392         (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
18393         (append-to-block Heap %edi  *eax *(eax+4))
18394         # . reclaim tmp
18395         81 0/subop/add %esp 8/imm32
18396         # .
18397         e9/jump $parse-mu-block:line-loop/disp32
18398       }
18399       # if slice-equal?(word-slice, "}") break
18400 $parse-mu-block:check-for-end:
18401       (slice-equal? %edx "}")
18402       3d/compare-eax-and 0/imm32/false
18403       0f 85/jump-if-!= break/disp32
18404       # if slice-ends-with?(word-slice, ":") parse named block and append
18405       {
18406 $parse-mu-block:check-for-named-block:
18407         # . eax = *(word-slice->end-1)
18408         8b/-> *(edx+4) 0/r32/eax
18409         48/decrement-eax
18410         8a/copy-byte *eax 0/r32/AL
18411         25/and-eax-with 0xff/imm32
18412         # . if (eax != ':') break
18413         3d/compare-eax-and 0x3a/imm32/colon
18414         0f 85/jump-if-!= break/disp32
18415         # if next-mu-token(line) != "{", abort
18416         (check-next-token-is-open-curly %ecx *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
18417         # skip ':'
18418         ff 1/subop/decrement *(edx+4)  # Slice-end
18419         # var tmp/eax: (handle block)
18420         68/push 0/imm32
18421         68/push 0/imm32
18422         89/<- %eax 4/r32/esp
18423         #
18424         (parse-mu-named-block %edx *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
18425         (append-to-block Heap %edi  *eax *(eax+4))
18426         # reclaim tmp
18427         81 0/subop/add %esp 8/imm32
18428         #
18429         e9/jump $parse-mu-block:line-loop/disp32
18430       }
18431       # if slice-equal?(word-slice, "var")
18432       {
18433 $parse-mu-block:check-for-var:
18434         (slice-equal? %edx "var")
18435         3d/compare-eax-and 0/imm32/false
18436         74/jump-if-= break/disp8
18437         # var tmp/eax: (handle block)
18438         68/push 0/imm32
18439         68/push 0/imm32
18440         89/<- %eax 4/r32/esp
18441         #
18442         (parse-mu-var-def %ecx *(ebp+0xc) %eax *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
18443         (append-to-block Heap %edi  *eax *(eax+4))
18444         # reclaim tmp
18445         81 0/subop/add %esp 8/imm32
18446         #
18447         e9/jump $parse-mu-block:line-loop/disp32
18448       }
18449 $parse-mu-block:regular-stmt:
18450       # otherwise
18451       # var tmp/eax: (handle block)
18452       68/push 0/imm32
18453       68/push 0/imm32
18454       89/<- %eax 4/r32/esp
18455       #
18456       (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
18457       (append-to-block Heap %edi  *eax *(eax+4))
18458       # reclaim tmp
18459       81 0/subop/add %esp 8/imm32
18460       #
18461       e9/jump loop/disp32
18462     } # end line loop
18463     (clean-up-blocks *(ebp+0xc) *Curr-block-depth *(ebp+0x10))
18464     # decrement *Curr-block-depth
18465     ff 1/subop/decrement *Curr-block-depth
18466     # pop(vars)
18467     (pop *(ebp+0xc))  # => eax
18468     (pop *(ebp+0xc))  # => eax
18469     (pop *(ebp+0xc))  # => eax
18470 $parse-mu-block:end:
18471     # . reclaim locals
18472     81 0/subop/add %esp 0x214/imm32
18473     # . restore registers
18474     5f/pop-to-edi
18475     5b/pop-to-ebx
18476     5a/pop-to-edx
18477     59/pop-to-ecx
18478     58/pop-to-eax
18479     # . epilogue
18480     89/<- %esp 5/r32/ebp
18481     5d/pop-to-ebp
18482     c3/return
18484 $parse-mu-block:abort:
18485     # error("'{' or '}' should be on its own line, but got '")
18486     (write-buffered *(ebp+0x18) "'{' or '}' should be on its own line, but got '")
18487     (rewind-stream %ecx)
18488     (write-stream-data *(ebp+0x18) %ecx)
18489     (write-buffered *(ebp+0x18) "'\n")
18490     (flush *(ebp+0x18))
18491     (stop *(ebp+0x1c) 1)
18492     # never gets here
18494 check-next-token-is-open-curly:  # line: (addr stream byte), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
18495     # . prologue
18496     55/push-ebp
18497     89/<- %ebp 4/r32/esp
18498     # . save registers
18499     50/push-eax
18500     52/push-edx
18501     # var word-slice/edx: slice
18502     68/push 0/imm32/end
18503     68/push 0/imm32/start
18504     89/<- %edx 4/r32/esp
18505     # word-slice = next-mu-token(line)
18506     (next-mu-token *(ebp+8) %edx)
18507     # if !slice-equal?(word-slice, "{") abort
18508     (slice-equal? %edx "{")  # => eax
18509     3d/compare-eax-and 0/imm32/false
18510     0f 84/jump-if-= $check-next-token-is-open-curly:abort/disp32
18511 $check-next-token-is-open-curly:end:
18512     # . reclaim locals
18513     81 0/subop/add %esp 8/imm32
18514     # . restore registers
18515     5a/pop-to-edx
18516     58/pop-to-eax
18517     # . epilogue
18518     89/<- %esp 5/r32/ebp
18519     5d/pop-to-ebp
18520     c3/return
18522 $check-next-token-is-open-curly:abort:
18523     # error("fn " fn ": unexpected ':'; did you forget a 'var'?")
18524     (write-buffered *(ebp+0x10) "fn ")
18525     8b/-> *(ebp+0xc) 0/r32/eax
18526     (lookup *eax *(eax+4))  # Function-name Function-name => eax
18527     (write-buffered *(ebp+0x10) %eax)
18528     (write-buffered *(ebp+0x10) ": unexpected ':'; did you forget a 'var'?\n")
18529     (flush *(ebp+0x10))
18530     (stop *(ebp+0x14) 1)
18531     # never gets here
18533 new-block-name:  # fn: (addr function), out: (addr handle var)
18534     # . prologue
18535     55/push-ebp
18536     89/<- %ebp 4/r32/esp
18537     # . save registers
18538     50/push-eax
18539     51/push-ecx
18540     52/push-edx
18541     # var n/ecx: int = len(fn->name) + 10 for an int + 2 for '$:'
18542     8b/-> *(ebp+8) 0/r32/eax
18543     (lookup *eax *(eax+4))  # Function-name Function-name => eax
18544     8b/-> *eax 0/r32/eax  # String-size
18545     05/add-to-eax 0xd/imm32  # 10 + 2 for '$:'
18546     89/<- %ecx 0/r32/eax
18547     # var name/edx: (stream byte n)
18548     29/subtract-from %esp 1/r32/ecx
18549     ff 6/subop/push %ecx
18550     68/push 0/imm32/read
18551     68/push 0/imm32/write
18552     89/<- %edx 4/r32/esp
18553     (clear-stream %edx)
18554     # eax = fn->name
18555     8b/-> *(ebp+8) 0/r32/eax
18556     (lookup *eax *(eax+4))  # Function-name Function-name => eax
18557     # construct result using Next-block-index (and increment it)
18558     (write %edx "$")
18559     (write %edx %eax)
18560     (write %edx ":")
18561     (write-int32-hex %edx *Next-block-index)
18562     ff 0/subop/increment *Next-block-index
18563     # var s/eax: slice = {name->data, name->data + name->write}  (clobbering edx)
18564     # . eax = name->write
18565     8b/-> *edx 0/r32/eax
18566     # . edx = name->data
18567     8d/copy-address *(edx+0xc) 2/r32/edx
18568     # . eax = name->write + name->data
18569     01/add-to %eax 2/r32/edx
18570     # . push {edx, eax}
18571     ff 6/subop/push %eax
18572     ff 6/subop/push %edx
18573     89/<- %eax 4/r32/esp
18574     # out = new literal(s)
18575     (new-literal Heap %eax *(ebp+0xc))
18576 #?     8b/-> *(ebp+0xc) 0/r32/eax
18577 #?     (write-buffered Stderr "type allocid in caller after new-literal: ")
18578 #?     (write-int32-hex-buffered Stderr *(eax+8))
18579 #?     (write-buffered Stderr " for var ")
18580 #?     (write-int32-hex-buffered Stderr %eax)
18581 #?     (write-buffered Stderr Newline)
18582 #?     (flush Stderr)
18583 $new-block-name:end:
18584     # . reclaim locals
18585     81 0/subop/add %ecx 0xc/imm32  # name.{read/write/len}
18586     81 0/subop/add %ecx 8/imm32  # slice
18587     01/add-to %esp 1/r32/ecx
18588     # . restore registers
18589     5a/pop-to-edx
18590     59/pop-to-ecx
18591     58/pop-to-eax
18592     # . epilogue
18593     89/<- %esp 5/r32/ebp
18594     5d/pop-to-ebp
18595     c3/return
18597 check-no-tokens-left:  # line: (addr stream byte)
18598     # . prologue
18599     55/push-ebp
18600     89/<- %ebp 4/r32/esp
18601     # . save registers
18602     50/push-eax
18603     51/push-ecx
18604     # var s/ecx: slice
18605     68/push 0/imm32/end
18606     68/push 0/imm32/start
18607     89/<- %ecx 4/r32/esp
18608     #
18609     (next-mu-token *(ebp+8) %ecx)
18610     # if slice-empty?(s) return
18611     (slice-empty? %ecx)
18612     3d/compare-eax-and 0/imm32/false
18613     75/jump-if-!= $check-no-tokens-left:end/disp8
18614     # if (slice-starts-with?(s, '#') return
18615     # . eax = *s->start
18616     8b/-> *edx 0/r32/eax
18617     8a/copy-byte *eax 0/r32/AL
18618     25/and-eax-with 0xff/imm32
18619     # . if (eax == '#') continue
18620     3d/compare-eax-and 0x23/imm32/hash
18621     74/jump-if-= $check-no-tokens-left:end/disp8
18622     # abort
18623     (write-buffered Stderr "'{' or '}' should be on its own line, but got '")
18624     (rewind-stream %ecx)
18625     (write-stream 2 %ecx)
18626     (write-buffered Stderr "'\n")
18627     (flush Stderr)
18628     # . syscall_exit(1)
18629     bb/copy-to-ebx  1/imm32
18630     e8/call syscall_exit/disp32
18631     # never gets here
18632 $check-no-tokens-left:end:
18633     # . reclaim locals
18634     81 0/subop/add %esp 8/imm32
18635     # . restore registers
18636     59/pop-to-ecx
18637     58/pop-to-eax
18638     # . epilogue
18639     89/<- %esp 5/r32/ebp
18640     5d/pop-to-ebp
18641     c3/return
18643 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)
18644     # pseudocode:
18645     #   var v: (handle var)
18646     #   new-literal(name, v)
18647     #   push(vars, {v, false})
18648     #   parse-mu-block(in, vars, fn, out)
18649     #   pop(vars)
18650     #   out->tag = block
18651     #   out->var = v
18652     #
18653     # . prologue
18654     55/push-ebp
18655     89/<- %ebp 4/r32/esp
18656     # . save registers
18657     50/push-eax
18658     51/push-ecx
18659     57/push-edi
18660     # var v/ecx: (handle var)
18661     68/push 0/imm32
18662     68/push 0/imm32
18663     89/<- %ecx 4/r32/esp
18664     #
18665     (new-literal Heap *(ebp+8) %ecx)
18666     # push(vars, v)
18667     (push *(ebp+0x10) *ecx)
18668     (push *(ebp+0x10) *(ecx+4))
18669     (push *(ebp+0x10) 0)  # false
18670     #
18671     (parse-mu-block *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20))
18672     # pop v off vars
18673     (pop *(ebp+0x10))  # => eax
18674     (pop *(ebp+0x10))  # => eax
18675     (pop *(ebp+0x10))  # => eax
18676     # var out-addr/edi: (addr stmt) = lookup(*out)
18677     8b/-> *(ebp+0x18) 7/r32/edi
18678     (lookup *edi *(edi+4))  # => eax
18679     89/<- %edi 0/r32/eax
18680     # out-addr->tag = named-block
18681     c7 0/subop/copy *edi 0/imm32/block  # Stmt-tag
18682     # out-addr->var = v
18683     8b/-> *ecx 0/r32/eax
18684     89/<- *(edi+0xc) 0/r32/eax  # Block-var
18685     8b/-> *(ecx+4) 0/r32/eax
18686     89/<- *(edi+0x10) 0/r32/eax  # Block-var
18687 $parse-mu-named-block:end:
18688     # . reclaim locals
18689     81 0/subop/add %esp 8/imm32
18690     # . restore registers
18691     5f/pop-to-edi
18692     59/pop-to-ecx
18693     58/pop-to-eax
18694     # . epilogue
18695     89/<- %esp 5/r32/ebp
18696     5d/pop-to-ebp
18697     c3/return
18699 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)
18700     # . prologue
18701     55/push-ebp
18702     89/<- %ebp 4/r32/esp
18703     # . save registers
18704     50/push-eax
18705     51/push-ecx
18706     52/push-edx
18707     56/push-esi
18708     57/push-edi
18709     # edi = out
18710     8b/-> *(ebp+0x10) 7/r32/edi
18711     # var word-slice/ecx: slice
18712     68/push 0/imm32/end
18713     68/push 0/imm32/start
18714     89/<- %ecx 4/r32/esp
18715     # var v/edx: (handle var)
18716     68/push 0/imm32
18717     68/push 0/imm32
18718     89/<- %edx 4/r32/esp
18719     # v = parse-var-with-type(next-mu-token(line))
18720     (next-mu-token *(ebp+8) %ecx)
18721     {
18722       # just for tests, support null fn
18723       8b/-> *(ebp+0x14) 0/r32/eax
18724       3d/compare-eax-and 0/imm32
18725       74/jump-if-= break/disp8
18726       (lookup *eax *(eax+4))  # Var-name Var-name => eax
18727     }
18728     (parse-var-with-type %ecx *(ebp+8) %edx %eax *(ebp+0x18) *(ebp+0x1c))
18729     # var v-addr/esi: (addr var)
18730     (lookup *edx *(edx+4))  # => eax
18731     89/<- %esi 0/r32/eax
18732     # v->block-depth = *Curr-block-depth
18733     8b/-> *Curr-block-depth 0/r32/eax
18734     89/<- *(esi+0x10) 0/r32/eax  # Var-block-depth
18735     # either v has no register and there's no more to this line
18736     81 7/subop/compare *(esi+0x18) 0/imm32
18737     {
18738       75/jump-if-!= break/disp8
18739       # if v-addr->type == byte, abort
18740       (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
18741       (simple-mu-type? %eax 8)  # byte => eax
18742       3d/compare-eax-and 0/imm32/false
18743       0f 85/jump-if-!= $parse-mu-var-def:error-byte-on-stack/disp32
18744       # ensure that there's nothing else on this line
18745       (next-mu-token *(ebp+8) %ecx)
18746       (slice-empty? %ecx)  # => eax
18747       3d/compare-eax-and 0/imm32/false
18748       0f 84/jump-if-= $parse-mu-var-def:error2/disp32
18749       #
18750       (new-var-def Heap  *edx *(edx+4)  %edi)
18751       e9/jump $parse-mu-var-def:update-vars/disp32
18752     }
18753     # or v has a register and there's more to this line
18754     {
18755       0f 84/jump-if-= break/disp32
18756       # if v-addr->type == byte, check for unsupported registers
18757       {
18758         (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
18759         (simple-mu-type? %eax 8)  # byte => eax
18760         3d/compare-eax-and 0/imm32/false
18761         74/jump-if-= break/disp8
18762         (lookup *(esi+0x18) *(esi+0x1c))  # => eax
18763         (string-equal? %eax "esi")  # => eax
18764         3d/compare-eax-and 0/imm32/false
18765         0f 85/jump-if-!= $parse-mu-var-def:error-byte-registers/disp32
18766         (lookup *(esi+0x18) *(esi+0x1c))  # => eax
18767         (string-equal? %eax "edi")  # => eax
18768         3d/compare-eax-and 0/imm32/false
18769         0f 85/jump-if-!= $parse-mu-var-def:error-byte-registers/disp32
18770       }
18771       # TODO: vars of type 'byte' should only be initialized by clearing to 0
18772       # ensure that the next word is '<-'
18773       (next-mu-token *(ebp+8) %ecx)
18774       (slice-equal? %ecx "<-")  # => eax
18775       3d/compare-eax-and 0/imm32/false
18776       0f 84/jump-if-= $parse-mu-var-def:error1/disp32
18777       #
18778       (new-reg-var-def Heap  *edx *(edx+4)  %edi)
18779       (lookup *edi *(edi+4))  # => eax
18780       (add-operation-and-inputs-to-stmt %eax *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
18781     }
18782 $parse-mu-var-def:update-vars:
18783     # push 'v' at end of function
18784     (push *(ebp+0xc) *edx)
18785     (push *(ebp+0xc) *(edx+4))
18786     (push *(ebp+0xc) 0)  # Live-var-register-spilled is unused during parsing
18787 $parse-mu-var-def:end:
18788     # . reclaim locals
18789     81 0/subop/add %esp 0x10/imm32
18790     # . restore registers
18791     5f/pop-to-edi
18792     5e/pop-to-esi
18793     5a/pop-to-edx
18794     59/pop-to-ecx
18795     58/pop-to-eax
18796     # . epilogue
18797     89/<- %esp 5/r32/ebp
18798     5d/pop-to-ebp
18799     c3/return
18801 $parse-mu-var-def:error1:
18802     (rewind-stream *(ebp+8))
18803     # error("register variable requires a valid instruction to initialize but got '" line "'\n")
18804     (write-buffered *(ebp+0x18) "register variable requires a valid instruction to initialize but got '")
18805     (flush *(ebp+0x18))
18806     (write-stream-data *(ebp+0x18) *(ebp+8))
18807     (write-buffered *(ebp+0x18) "'\n")
18808     (flush *(ebp+0x18))
18809     (stop *(ebp+0x1c) 1)
18810     # never gets here
18812 $parse-mu-var-def:error2:
18813     # error("fn " fn ": var " var ": variables on the stack can't take an initializer\n")
18814     (write-buffered *(ebp+0x18) "fn ")
18815     8b/-> *(ebp+0x14) 0/r32/eax
18816     (lookup *eax *(eax+4))  # Function-name Function-name => eax
18817     (write-buffered *(ebp+0x18) %eax)
18818     (write-buffered *(ebp+0x18) ": var ")
18819     # var v-addr/eax: (addr var) = lookup(v)
18820     (lookup *edx *(edx+4))  # => eax
18821     (lookup *eax *(eax+4))  # Var-name Var-name => eax
18822     (write-buffered *(ebp+0x18) %eax)
18823     (write-buffered *(ebp+0x18) ": variables on the stack can't take an initializer\n")
18824     (flush *(ebp+0x18))
18825     (stop *(ebp+0x1c) 1)
18826     # never gets here
18828 $parse-mu-var-def:error-byte-on-stack:
18829     # error("fn " fn ": var '" var "' of type 'byte' cannot be on the stack\n")
18830     (write-buffered *(ebp+0x18) "fn ")
18831     8b/-> *(ebp+0x14) 0/r32/eax
18832     (lookup *eax *(eax+4))  # Function-name Function-name => eax
18833     (write-buffered *(ebp+0x18) %eax)
18834     (write-buffered *(ebp+0x18) ": var '")
18835     # var v-addr/eax: (addr var) = lookup(v)
18836     (lookup *edx *(edx+4))  # => eax
18837     (lookup *eax *(eax+4))  # Var-name Var-name => eax
18838     (write-buffered *(ebp+0x18) %eax)
18839     (write-buffered *(ebp+0x18) "' of type 'byte' cannot be on the stack\n")
18840     (flush *(ebp+0x18))
18841     (stop *(ebp+0x1c) 1)
18842     # never gets here
18844 $parse-mu-var-def:error-byte-registers:
18845     # error("fn " fn ": var '" var "' of type 'byte' cannot be in esi or edi\n")
18846     (write-buffered *(ebp+0x18) "fn ")
18847     8b/-> *(ebp+0x14) 0/r32/eax
18848     (lookup *eax *(eax+4))  # Function-name Function-name => eax
18849     (write-buffered *(ebp+0x18) %eax)
18850     (write-buffered *(ebp+0x18) ": var '")
18851     # var v-addr/eax: (addr var) = lookup(v)
18852     (lookup *edx *(edx+4))  # => eax
18853     (lookup *eax *(eax+4))  # Var-name Var-name => eax
18854     (write-buffered *(ebp+0x18) %eax)
18855     (write-buffered *(ebp+0x18) "' of type 'byte' cannot be in esi or edi\n")
18856     (flush *(ebp+0x18))
18857     (stop *(ebp+0x1c) 1)
18858     # never gets here
18860 test-parse-mu-var-def:
18861     # 'var n: int'
18862     # . prologue
18863     55/push-ebp
18864     89/<- %ebp 4/r32/esp
18865     # setup
18866     8b/-> *Primitive-type-ids 0/r32/eax
18867     89/<- *Type-id 0/r32/eax  # stream-write
18868     (clear-stream _test-input-stream)
18869     (write _test-input-stream "n: int\n")  # caller has consumed the 'var'
18870     c7 0/subop/copy *Curr-block-depth 1/imm32
18871     # var out/esi: (handle stmt)
18872     68/push 0/imm32
18873     68/push 0/imm32
18874     89/<- %esi 4/r32/esp
18875     # var vars/ecx: (stack (addr var) 16)
18876     81 5/subop/subtract %esp 0xc0/imm32
18877     68/push 0xc0/imm32/size
18878     68/push 0/imm32/top
18879     89/<- %ecx 4/r32/esp
18880     (clear-stack %ecx)
18881     # convert
18882     (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0)
18883     # var out-addr/esi: (addr stmt)
18884     (lookup *esi *(esi+4))  # => eax
18885     89/<- %esi 0/r32/eax
18886     #
18887     (check-ints-equal *esi 2 "F - test-parse-mu-var-def/tag")  # Stmt-tag is var-def
18888     # var v/ecx: (addr var) = lookup(out->var)
18889     (lookup *(esi+4) *(esi+8))  # Vardef-var Vardef-var => eax
18890     89/<- %ecx 0/r32/eax
18891     # v->name
18892     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
18893     (check-strings-equal %eax "n" "F - test-parse-mu-var-def/var-name")
18894     # v->register
18895     (check-ints-equal *(ecx+0x18) 0 "F - test-parse-mu-var-def/var-register")  # Var-register
18896     # v->block-depth
18897     (check-ints-equal *(ecx+0x10) 1 "F - test-parse-mu-var-def/output-block-depth")  # Var-block-depth
18898     # v->type == int
18899     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
18900     (check-ints-equal *eax 1 "F - test-parse-mu-var-def/var-type:0")  # Type-tree-is-atom
18901     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-var-def/var-type:1")  # Type-tree-value
18902     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-var-def/var-type:2")  # Type-tree-right
18903     # . epilogue
18904     89/<- %esp 5/r32/ebp
18905     5d/pop-to-ebp
18906     c3/return
18908 test-parse-mu-reg-var-def:
18909     # 'var n/eax: int <- copy 0'
18910     # . prologue
18911     55/push-ebp
18912     89/<- %ebp 4/r32/esp
18913     # setup
18914     8b/-> *Primitive-type-ids 0/r32/eax
18915     89/<- *Type-id 0/r32/eax  # stream-write
18916     (clear-stream _test-input-stream)
18917     (write _test-input-stream "n/eax: int <- copy 0\n")  # caller has consumed the 'var'
18918     c7 0/subop/copy *Curr-block-depth 1/imm32
18919     # var out/esi: (handle stmt)
18920     68/push 0/imm32
18921     68/push 0/imm32
18922     89/<- %esi 4/r32/esp
18923     # var vars/ecx: (stack (addr var) 16)
18924     81 5/subop/subtract %esp 0xc0/imm32
18925     68/push 0xc0/imm32/size
18926     68/push 0/imm32/top
18927     89/<- %ecx 4/r32/esp
18928     (clear-stack %ecx)
18929     # convert
18930     (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0)
18931     # var out-addr/esi: (addr stmt)
18932     (lookup *esi *(esi+4))  # => eax
18933     89/<- %esi 0/r32/eax
18934     #
18935     (check-ints-equal *esi 3 "F - test-parse-mu-reg-var-def/tag")  # Stmt-tag is reg-var-def
18936     # var v/ecx: (addr var) = lookup(out->outputs->value)
18937     # . eax: (addr stmt-var) = lookup(out->outputs)
18938     (lookup *(esi+0x14) *(esi+0x18))  # Regvardef-outputs Regvardef-outputs => eax
18939     # .
18940     (check-ints-equal *(eax+8) 0 "F - test-parse-mu-reg-var-def/single-output")  # Stmt-var-next
18941     # . eax: (addr var) = lookup(eax->value)
18942     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
18943     # . ecx = eax
18944     89/<- %ecx 0/r32/eax
18945     # v->name
18946     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
18947     (check-strings-equal %eax "n" "F - test-parse-mu-reg-var-def/output-name")  # Var-name
18948     # v->register
18949     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
18950     (check-strings-equal %eax "eax" "F - test-parse-mu-reg-var-def/output-register")
18951     # v->block-depth
18952     (check-ints-equal *(ecx+0x10) 1 "F - test-parse-mu-reg-var-def/output-block-depth")  # Var-block-depth
18953     # v->type == int
18954     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
18955     (check-ints-equal *eax 1 "F - test-parse-mu-reg-var-def/output-type:0")  # Type-tree-is-atom
18956     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-reg-var-def/output-type:1")  # Type-tree-value
18957     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-reg-var-def/output-type:2")  # Type-tree-right
18958     # . epilogue
18959     89/<- %esp 5/r32/ebp
18960     5d/pop-to-ebp
18961     c3/return
18963 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)
18964     # pseudocode:
18965     #   var name: slice
18966     #   allocate(Heap, Stmt-size, out)
18967     #   var out-addr: (addr stmt) = lookup(*out)
18968     #   out-addr->tag = stmt
18969     #   if stmt-has-outputs?(line)
18970     #     while true
18971     #       name = next-mu-token(line)
18972     #       if (name == '<-') break
18973     #       assert(identifier?(name))
18974     #       var v: (handle var) = lookup-var(name, vars)
18975     #       out-addr->outputs = append(v, out-addr->outputs)
18976     #   add-operation-and-inputs-to-stmt(out-addr, line, vars)
18977     #
18978     # . prologue
18979     55/push-ebp
18980     89/<- %ebp 4/r32/esp
18981     # . save registers
18982     50/push-eax
18983     51/push-ecx
18984     52/push-edx
18985     53/push-ebx
18986     57/push-edi
18987     # var name/ecx: slice
18988     68/push 0/imm32/end
18989     68/push 0/imm32/start
18990     89/<- %ecx 4/r32/esp
18991     # var is-deref?/edx: boolean = false
18992     ba/copy-to-edx 0/imm32/false
18993     # var v: (handle var)
18994     68/push 0/imm32
18995     68/push 0/imm32
18996     89/<- %ebx 4/r32/esp
18997     #
18998     (allocate Heap *Stmt-size *(ebp+0x14))
18999     # var out-addr/edi: (addr stmt) = lookup(*out)
19000     8b/-> *(ebp+0x14) 7/r32/edi
19001     (lookup *edi *(edi+4))  # => eax
19002     89/<- %edi 0/r32/eax
19003     # out-addr->tag = 1/stmt
19004     c7 0/subop/copy *edi 1/imm32/stmt1  # Stmt-tag
19005     {
19006       (stmt-has-outputs? *(ebp+8))
19007       3d/compare-eax-and 0/imm32/false
19008       0f 84/jump-if-= break/disp32
19009       {
19010 $parse-mu-stmt:read-outputs:
19011         # name = next-mu-token(line)
19012         (next-mu-token *(ebp+8) %ecx)
19013         # if slice-empty?(word-slice) break
19014         (slice-empty? %ecx)  # => eax
19015         3d/compare-eax-and 0/imm32/false
19016         0f 85/jump-if-!= break/disp32
19017         # if (name == "<-") break
19018         (slice-equal? %ecx "<-")  # => eax
19019         3d/compare-eax-and 0/imm32/false
19020         0f 85/jump-if-!= break/disp32
19021         # if slice-starts-with?(name, "*") abort
19022         8b/-> *ecx 0/r32/eax  # Slice-start
19023         8a/copy-byte *eax 0/r32/AL
19024         25/and-eax-with 0xff/imm32
19025         3d/compare-eax-and 0x2a/imm32/asterisk
19026         0f 84/jump-if-= $parse-mu-stmt:error-output-dereferenced/disp32
19027         # assert(identifier?(name))
19028         (identifier? %ecx)  # => eax
19029         3d/compare-eax-and 0/imm32/false
19030         0f 84/jump-if-= $parse-mu-stmt:abort/disp32
19031         #
19032         (lookup-var %ecx *(ebp+0xc) %ebx *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
19033         8d/copy-address *(edi+0x14) 0/r32/eax  # Stmt1-outputs
19034         (append-stmt-var Heap  *ebx *(ebx+4)  *(edi+0x14) *(edi+0x18)  0  %eax)  # Stmt1-outputs
19035         #
19036         e9/jump loop/disp32
19037       }
19038     }
19039     (add-operation-and-inputs-to-stmt %edi *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
19040 $parse-mu-stmt:end:
19041     # . reclaim locals
19042     81 0/subop/add %esp 0x10/imm32
19043     # . restore registers
19044     5f/pop-to-edi
19045     5b/pop-to-ebx
19046     5a/pop-to-edx
19047     59/pop-to-ecx
19048     58/pop-to-eax
19049     # . epilogue
19050     89/<- %esp 5/r32/ebp
19051     5d/pop-to-ebp
19052     c3/return
19054 $parse-mu-stmt:abort:
19055     # error("invalid identifier '" name "'\n")
19056     (write-buffered *(ebp+0x18) "fn ")
19057     8b/-> *(ebp+0x10) 0/r32/eax
19058     (lookup *eax *(eax+4))  # Function-name Function-name => eax
19059     (write-buffered *(ebp+0x18) %eax)
19060     (write-buffered *(ebp+0x18) ": invalid identifier '")
19061     (write-slice-buffered *(ebp+0x18) %ecx)
19062     (write-buffered *(ebp+0x18) "'\n")
19063     (flush *(ebp+0x18))
19064     (stop *(ebp+0x1c) 1)
19065     # never gets here
19067 $parse-mu-stmt:error-output-dereferenced:
19068     # error("invalid identifier '" name "'\n")
19069     (write-buffered *(ebp+0x18) "fn ")
19070     8b/-> *(ebp+0x10) 0/r32/eax
19071     (lookup *eax *(eax+4))  # Function-name Function-name => eax
19072     (write-buffered *(ebp+0x18) %eax)
19073     (write-buffered *(ebp+0x18) ": output '")
19074     (write-slice-buffered *(ebp+0x18) %ecx)
19075     (write-buffered *(ebp+0x18) "' should write to a register, and therefore cannot be dereferenced\n")
19076     (flush *(ebp+0x18))
19077     (stop *(ebp+0x1c) 1)
19078     # never gets here
19080 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)
19081     # pseudocode:
19082     #   stmt->name = slice-to-string(next-mu-token(line))
19083     #   while true
19084     #     name = next-mu-token(line)
19085     #     v = lookup-var-or-literal(name)
19086     #     stmt->inouts = append(v, stmt->inouts)
19087     #
19088     # . prologue
19089     55/push-ebp
19090     89/<- %ebp 4/r32/esp
19091     # . save registers
19092     50/push-eax
19093     51/push-ecx
19094     52/push-edx
19095     53/push-ebx
19096     56/push-esi
19097     57/push-edi
19098     # edi = stmt
19099     8b/-> *(ebp+8) 7/r32/edi
19100     # var name/ecx: slice
19101     68/push 0/imm32/end
19102     68/push 0/imm32/start
19103     89/<- %ecx 4/r32/esp
19104     # var is-deref?/edx: boolean = false
19105     ba/copy-to-edx 0/imm32/false
19106     # var v/esi: (handle var)
19107     68/push 0/imm32
19108     68/push 0/imm32
19109     89/<- %esi 4/r32/esp
19110 $add-operation-and-inputs-to-stmt:read-operation:
19111     (next-mu-token *(ebp+0xc) %ecx)
19112     8d/copy-address *(edi+4) 0/r32/eax  # Stmt1-operation or Regvardef-operationStmt1-operation or Regvardef-operation
19113     (slice-to-string Heap %ecx %eax)
19114     # var is-get?/ebx: boolean = (name == "get")
19115     (slice-equal? %ecx "get")  # => eax
19116     89/<- %ebx 0/r32/eax
19117     {
19118 $add-operation-and-inputs-to-stmt:read-inouts:
19119       # name = next-mu-token(line)
19120       (next-mu-token *(ebp+0xc) %ecx)
19121       # if slice-empty?(word-slice) break
19122       (slice-empty? %ecx)  # => eax
19123       3d/compare-eax-and 0/imm32/false
19124       0f 85/jump-if-!= break/disp32
19125       # if (name == "<-") abort
19126       (slice-equal? %ecx "<-")
19127       3d/compare-eax-and 0/imm32/false
19128       0f 85/jump-if-!= $add-operation-and-inputs-to-stmt:abort/disp32
19129       # if (get? && second operand) lookup or create offset
19130       {
19131         81 7/subop/compare %ebx 0/imm32/false
19132         74/jump-if-= break/disp8
19133         (lookup *(edi+0xc) *(edi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
19134         3d/compare-eax-and 0/imm32
19135         74/jump-if-= break/disp8
19136         (lookup-or-create-constant %eax %ecx %esi)
19137 #?         (lookup *esi *(esi+4))
19138 #?         (write-buffered Stderr "creating new output var ")
19139 #?         (write-int32-hex-buffered Stderr %eax)
19140 #?         (write-buffered Stderr " for field called ")
19141 #?         (write-slice-buffered Stderr %ecx)
19142 #?         (write-buffered Stderr "; var name ")
19143 #?         (lookup *eax *(eax+4))  # Var-name
19144 #?         (write-buffered Stderr %eax)
19145 #?         (write-buffered Stderr Newline)
19146 #?         (flush Stderr)
19147         e9/jump $add-operation-and-inputs-to-stmt:save-var/disp32
19148       }
19149       # is-deref? = false
19150       ba/copy-to-edx 0/imm32/false
19151       # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
19152       8b/-> *ecx 0/r32/eax  # Slice-start
19153       8a/copy-byte *eax 0/r32/AL
19154       25/and-eax-with 0xff/imm32
19155       3d/compare-eax-and 0x2a/imm32/asterisk
19156       {
19157         75/jump-if-!= break/disp8
19158 $add-operation-and-inputs-to-stmt:inout-is-deref:
19159         ff 0/subop/increment *ecx
19160         ba/copy-to-edx 1/imm32/true
19161       }
19162       (lookup-var-or-literal %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
19163       # if (deref?) some additional checks
19164       81 7/subop/compare %edx 0/imm32/false
19165       {
19166         74/jump-if-= break/disp8
19167         # if var is not in register, abort
19168         (lookup *esi *(esi+4))  # => eax
19169         81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
19170         0f 84/jump-if-= $add-operation-and-inputs-to-stmt:error-deref-on-stack/disp32
19171         # if var is not an address, abort
19172         (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
19173         (mu-addr-type? %eax)  # => eax
19174         3d/compare-eax-and 0/imm32/false
19175         0f 84/jump-if-= $add-operation-and-inputs-to-stmt:error-deref-non-addr/disp32
19176       }
19177 $add-operation-and-inputs-to-stmt:save-var:
19178       8d/copy-address *(edi+0xc) 0/r32/eax
19179       (append-stmt-var Heap  *esi *(esi+4)  *(edi+0xc) *(edi+0x10)  %edx  %eax)  # Stmt1-inouts or Regvardef-inouts
19180       #
19181       e9/jump loop/disp32
19182     }
19183 $add-operation-and-inputs-to-stmt:end:
19184     # . reclaim locals
19185     81 0/subop/add %esp 0x10/imm32
19186     # . restore registers
19187     5f/pop-to-edi
19188     5e/pop-to-esi
19189     5b/pop-to-ebx
19190     5a/pop-to-edx
19191     59/pop-to-ecx
19192     58/pop-to-eax
19193     # . epilogue
19194     89/<- %esp 5/r32/ebp
19195     5d/pop-to-ebp
19196     c3/return
19198 $add-operation-and-inputs-to-stmt:abort:
19199     # error("fn ___: invalid identifier in '" line "'\n")
19200     (write-buffered *(ebp+0x18) "fn ")
19201     8b/-> *(ebp+0x14) 0/r32/eax
19202     (lookup *eax *(eax+4))  # Function-name Function-name => eax
19203     (write-buffered *(ebp+0x18) %eax)
19204     (rewind-stream *(ebp+0xc))
19205     (write-buffered *(ebp+0x18) ": invalid identifier in '")
19206     (write-stream-data *(ebp+0x18) *(ebp+0xc))
19207     (write-buffered *(ebp+0x18) "'\n")
19208     (flush *(ebp+0x18))
19209     (stop *(ebp+0x1c) 1)
19210     # never gets here
19212 $add-operation-and-inputs-to-stmt:error-deref-on-stack:
19213     # error("fn ___: cannot dereference var ___ on stack\n")
19214     (write-buffered *(ebp+0x18) "fn ")
19215     8b/-> *(ebp+0x14) 0/r32/eax
19216     (lookup *eax *(eax+4))  # Function-name Function-name => eax
19217     (write-buffered *(ebp+0x18) %eax)
19218     (rewind-stream *(ebp+0xc))
19219     (write-buffered *(ebp+0x18) ": cannot dereference var '")
19220     (lookup *esi *(esi+4))  # => eax
19221     (lookup *eax *(eax+4))  # Var-name Var-name => eax
19222     (write-buffered *(ebp+0x18) %eax)
19223     (write-buffered *(ebp+0x18) "' on stack\n")
19224     (flush *(ebp+0x18))
19225     (stop *(ebp+0x1c) 1)
19226     # never gets here
19228 $add-operation-and-inputs-to-stmt:error-deref-non-addr:
19229     # error("fn ___: cannot dereference non-addr var ___\n")
19230     (write-buffered *(ebp+0x18) "fn ")
19231     8b/-> *(ebp+0x14) 0/r32/eax
19232     (lookup *eax *(eax+4))  # Function-name Function-name => eax
19233     (write-buffered *(ebp+0x18) %eax)
19234     (rewind-stream *(ebp+0xc))
19235     (write-buffered *(ebp+0x18) ": cannot dereference non-addr var '")
19236     (lookup *esi *(esi+4))  # => eax
19237     (lookup *eax *(eax+4))  # Var-name Var-name => eax
19238     (write-buffered *(ebp+0x18) %eax)
19239     (write-buffered *(ebp+0x18) "'\n")
19240     (flush *(ebp+0x18))
19241     (stop *(ebp+0x1c) 1)
19242     # never gets here
19244 stmt-has-outputs?:  # line: (addr stream byte) -> result/eax: boolean
19245     # . prologue
19246     55/push-ebp
19247     89/<- %ebp 4/r32/esp
19248     # . save registers
19249     51/push-ecx
19250     # var word-slice/ecx: slice
19251     68/push 0/imm32/end
19252     68/push 0/imm32/start
19253     89/<- %ecx 4/r32/esp
19254     # result = false
19255     b8/copy-to-eax 0/imm32/false
19256     (rewind-stream *(ebp+8))
19257     {
19258       (next-mu-token *(ebp+8) %ecx)
19259       # if slice-empty?(word-slice) break
19260       (slice-empty? %ecx)
19261       3d/compare-eax-and 0/imm32/false
19262       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
19263       0f 85/jump-if-!= break/disp32
19264       # if slice-starts-with?(word-slice, '#') break
19265       # . eax = *word-slice->start
19266       8b/-> *ecx 0/r32/eax
19267       8a/copy-byte *eax 0/r32/AL
19268       25/and-eax-with 0xff/imm32
19269       # . if (eax == '#') break
19270       3d/compare-eax-and 0x23/imm32/hash
19271       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
19272       0f 84/jump-if-= break/disp32
19273       # if slice-equal?(word-slice, '<-') return true
19274       (slice-equal? %ecx "<-")
19275       3d/compare-eax-and 0/imm32/false
19276       74/jump-if-= loop/disp8
19277       b8/copy-to-eax 1/imm32/true
19278     }
19279 $stmt-has-outputs:end:
19280     (rewind-stream *(ebp+8))
19281     # . reclaim locals
19282     81 0/subop/add %esp 8/imm32
19283     # . restore registers
19284     59/pop-to-ecx
19285     # . epilogue
19286     89/<- %esp 5/r32/ebp
19287     5d/pop-to-ebp
19288     c3/return
19290 # if 'name' starts with a digit, create a new literal var for it
19291 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found
19292 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)
19293     # . prologue
19294     55/push-ebp
19295     89/<- %ebp 4/r32/esp
19296     # . save registers
19297     50/push-eax
19298     51/push-ecx
19299     56/push-esi
19300     # esi = name
19301     8b/-> *(ebp+8) 6/r32/esi
19302     # if slice-empty?(name) abort
19303     (slice-empty? %esi)  # => eax
19304     3d/compare-eax-and 0/imm32/false
19305     0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32
19306     # var c/ecx: byte = *name->start
19307     8b/-> *esi 1/r32/ecx
19308     8a/copy-byte *ecx 1/r32/CL
19309     81 4/subop/and %ecx 0xff/imm32
19310     # if (decimal-digit?(c) || c == '-') return new var(name)
19311     {
19312       81 7/subop/compare %ecx 0x2d/imm32/dash
19313       74/jump-if-= $lookup-var-or-literal:literal/disp8
19314       (decimal-digit? %ecx)  # => eax
19315       3d/compare-eax-and 0/imm32/false
19316       74/jump-if-= break/disp8
19317 $lookup-var-or-literal:literal:
19318       (new-literal-integer Heap %esi *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
19319       eb/jump $lookup-var-or-literal:end/disp8
19320     }
19321     # else if (c == '"') return new var(name)
19322     {
19323       81 7/subop/compare %ecx 0x22/imm32/dquote
19324       75/jump-if-!= break/disp8
19325 $lookup-var-or-literal:literal-string:
19326       (new-literal-string Heap %esi *(ebp+0x10))
19327       eb/jump $lookup-var-or-literal:end/disp8
19328     }
19329     # otherwise return lookup-var(name, vars)
19330     {
19331 $lookup-var-or-literal:var:
19332       (lookup-var %esi *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
19333     }
19334 $lookup-var-or-literal:end:
19335     # . restore registers
19336     5e/pop-to-esi
19337     59/pop-to-ecx
19338     58/pop-to-eax
19339     # . epilogue
19340     89/<- %esp 5/r32/ebp
19341     5d/pop-to-ebp
19342     c3/return
19344 $lookup-var-or-literal:abort:
19345     (write-buffered *(ebp+0x18) "fn ")
19346     8b/-> *(ebp+0x14) 0/r32/eax
19347     (lookup *eax *(eax+4))  # Function-name Function-name => eax
19348     (write-buffered *(ebp+0x18) %eax)
19349     (write-buffered *(ebp+0x18) ": empty variable!")
19350     (flush *(ebp+0x18))
19351     (stop *(ebp+0x1c) 1)
19352     # never gets here
19354 # return first 'name' from the top (back) of 'vars' and abort if not found
19355 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)
19356     # . prologue
19357     55/push-ebp
19358     89/<- %ebp 4/r32/esp
19359     # . save registers
19360     50/push-eax
19361     #
19362     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
19363     # if (*out == 0) abort
19364     8b/-> *(ebp+0x10) 0/r32/eax
19365     81 7/subop/compare *eax 0/imm32
19366     74/jump-if-= $lookup-var:abort/disp8
19367 $lookup-var:end:
19368     # . restore registers
19369     58/pop-to-eax
19370     # . epilogue
19371     89/<- %esp 5/r32/ebp
19372     5d/pop-to-ebp
19373     c3/return
19375 $lookup-var:abort:
19376     (write-buffered *(ebp+0x18) "fn ")
19377     8b/-> *(ebp+0x14) 0/r32/eax
19378     (lookup *eax *(eax+4))  # Function-name Function-name => eax
19379     (write-buffered *(ebp+0x18) %eax)
19380     (write-buffered *(ebp+0x18) ": unknown variable '")
19381     (write-slice-buffered *(ebp+0x18) *(ebp+8))
19382     (write-buffered *(ebp+0x18) "'\n")
19383     (flush *(ebp+0x18))
19384     (stop *(ebp+0x1c) 1)
19385     # never gets here
19387 # return first 'name' from the top (back) of 'vars', and 0/null if not found
19388 # ensure that 'name' if in a register is the topmost variable in that register
19389 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)
19390     # pseudocode:
19391     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
19392     #   var min = vars->data
19393     #   while curr >= min
19394     #     var v: (handle var) = *curr
19395     #     if v->name == name
19396     #       return
19397     #     curr -= 12
19398     #
19399     # . prologue
19400     55/push-ebp
19401     89/<- %ebp 4/r32/esp
19402     # . save registers
19403     50/push-eax
19404     51/push-ecx
19405     52/push-edx
19406     53/push-ebx
19407     56/push-esi
19408     57/push-edi
19409     # clear out
19410     (zero-out *(ebp+0x10) *Handle-size)
19411     # esi = vars
19412     8b/-> *(ebp+0xc) 6/r32/esi
19413     # ebx = vars->top
19414     8b/-> *esi 3/r32/ebx
19415     # if (vars->top > vars->size) abort
19416     3b/compare<- *(esi+4) 0/r32/eax
19417     0f 8f/jump-if-> $lookup-var-helper:error1/disp32
19418     # var min/edx: (addr handle var) = vars->data
19419     8d/copy-address *(esi+8) 2/r32/edx
19420     # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
19421     8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
19422     # var var-in-reg/edi: 16 addrs
19423     68/push 0/imm32
19424     68/push 0/imm32
19425     68/push 0/imm32
19426     68/push 0/imm32
19427     68/push 0/imm32
19428     68/push 0/imm32
19429     68/push 0/imm32
19430     68/push 0/imm32
19431     68/push 0/imm32
19432     68/push 0/imm32
19433     68/push 0/imm32
19434     68/push 0/imm32
19435     68/push 0/imm32
19436     68/push 0/imm32
19437     68/push 0/imm32
19438     68/push 0/imm32
19439     89/<- %edi 4/r32/esp
19440     {
19441 $lookup-var-helper:loop:
19442       # if (curr < min) return
19443       39/compare %ebx 2/r32/edx
19444       0f 82/jump-if-addr< break/disp32
19445       # var v/ecx: (addr var) = lookup(*curr)
19446       (lookup *ebx *(ebx+4))  # => eax
19447       89/<- %ecx 0/r32/eax
19448       # var vn/eax: (addr array byte) = lookup(v->name)
19449       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
19450       # if (vn == name) return curr
19451       (slice-equal? *(ebp+8) %eax)  # => eax
19452       3d/compare-eax-and 0/imm32/false
19453       {
19454         74/jump-if-= break/disp8
19455 $lookup-var-helper:found:
19456         # var vr/eax: (addr array byte) = lookup(v->register)
19457         (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
19458         3d/compare-eax-and 0/imm32
19459         {
19460           74/jump-if-= break/disp8
19461 $lookup-var-helper:found-register:
19462           # var reg/eax: int = get(Registers, vr)
19463           (get Mu-registers-unique %eax 0xc "Mu-registers-unique")  # => eax
19464           8b/-> *eax 0/r32/eax
19465           # if (var-in-reg[reg]) error
19466           8b/-> *(edi+eax<<2) 0/r32/eax
19467           3d/compare-eax-and 0/imm32
19468           0f 85/jump-if-!= $lookup-var-helper:error2/disp32
19469         }
19470 $lookup-var-helper:return:
19471         # esi = out
19472         8b/-> *(ebp+0x10) 6/r32/esi
19473         # *out = *curr
19474         8b/-> *ebx 0/r32/eax
19475         89/<- *esi 0/r32/eax
19476         8b/-> *(ebx+4) 0/r32/eax
19477         89/<- *(esi+4) 0/r32/eax
19478         # return
19479         eb/jump $lookup-var-helper:end/disp8
19480       }
19481       # 'name' not yet found; update var-in-reg if v in register
19482       # . var vr/eax: (addr array byte) = lookup(v->register)
19483       (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
19484       # . if (vr == 0) continue
19485       3d/compare-eax-and 0/imm32
19486       74/jump-if-= $lookup-var-helper:continue/disp8
19487       # . var reg/eax: int = get(Registers, vr)
19488       (get Mu-registers-unique %eax 0xc "Mu-registers-unique")  # => eax
19489       8b/-> *eax 0/r32/eax
19490       # . var-in-reg[reg] = v
19491       89/<- *(edi+eax<<2) 1/r32/ecx
19492 $lookup-var-helper:continue:
19493       # curr -= 12
19494       81 5/subop/subtract %ebx 0xc/imm32
19495       e9/jump loop/disp32
19496     }
19497 $lookup-var-helper:end:
19498     # . reclaim locals
19499     81 0/subop/add %esp 0x40/imm32
19500     # . restore registers
19501     5f/pop-to-edi
19502     5e/pop-to-esi
19503     5b/pop-to-ebx
19504     5a/pop-to-edx
19505     59/pop-to-ecx
19506     58/pop-to-eax
19507     # . epilogue
19508     89/<- %esp 5/r32/ebp
19509     5d/pop-to-ebp
19510     c3/return
19512 $lookup-var-helper:error1:
19513     (write-buffered *(ebp+0x18) "fn ")
19514     8b/-> *(ebp+0x14) 0/r32/eax
19515     (lookup *eax *(eax+4))  # Function-name Function-name => eax
19516     (write-buffered *(ebp+0x18) %eax)
19517     (write-buffered *(ebp+0x18) ": malformed stack when looking up '")
19518     (write-slice-buffered *(ebp+0x18) *(ebp+8))
19519     (write-buffered *(ebp+0x18) "'\n")
19520     (flush *(ebp+0x18))
19521     (stop *(ebp+0x1c) 1)
19522     # never gets here
19524 $lookup-var-helper:error2:
19525     # eax contains the conflicting var at this point
19526     (write-buffered *(ebp+0x18) "fn ")
19527     50/push-eax
19528     8b/-> *(ebp+0x14) 0/r32/eax
19529     (lookup *eax *(eax+4))  # Function-name Function-name => eax
19530     (write-buffered *(ebp+0x18) %eax)
19531     58/pop-eax
19532     (write-buffered *(ebp+0x18) ": register ")
19533     50/push-eax
19534     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
19535     (write-buffered *(ebp+0x18) %eax)
19536     58/pop-to-eax
19537     (write-buffered *(ebp+0x18) " reads var '")
19538     (write-slice-buffered *(ebp+0x18) *(ebp+8))
19539     (write-buffered *(ebp+0x18) "' after writing var '")
19540     (lookup *eax *(eax+4))  # Var-name Var-name => eax
19541     (write-buffered *(ebp+0x18) %eax)
19542     (write-buffered *(ebp+0x18) "'\n")
19543     (flush *(ebp+0x18))
19544     (stop *(ebp+0x1c) 1)
19545     # never gets here
19547 dump-vars:  # vars: (addr stack live-var)
19548     # pseudocode:
19549     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
19550     #   var min = vars->data
19551     #   while curr >= min
19552     #     var v: (handle var) = *curr
19553     #     print v
19554     #     curr -= 12
19555     #
19556     # . prologue
19557     55/push-ebp
19558     89/<- %ebp 4/r32/esp
19559     # . save registers
19560     52/push-edx
19561     53/push-ebx
19562     56/push-esi
19563     # esi = vars
19564     8b/-> *(ebp+8) 6/r32/esi
19565     # ebx = vars->top
19566     8b/-> *esi 3/r32/ebx
19567     # var min/edx: (addr handle var) = vars->data
19568     8d/copy-address *(esi+8) 2/r32/edx
19569     # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
19570     8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
19571     {
19572 $dump-vars:loop:
19573       # if (curr < min) return
19574       39/compare %ebx 2/r32/edx
19575       0f 82/jump-if-addr< break/disp32
19576       #
19577       (write-buffered Stderr "  var@")
19578       (dump-var 2 %ebx)
19579       # curr -= 12
19580       81 5/subop/subtract %ebx 0xc/imm32
19581       e9/jump loop/disp32
19582     }
19583 $dump-vars:end:
19584     # . restore registers
19585     5e/pop-to-esi
19586     5b/pop-to-ebx
19587     5a/pop-to-edx
19588     # . epilogue
19589     89/<- %esp 5/r32/ebp
19590     5d/pop-to-ebp
19591     c3/return
19593 == data
19594 # Like Registers, but no esp or ebp
19595 Mu-registers:  # (addr stream {(handle array byte), int})
19596   # a table is a stream
19597   0xa8/imm32/write
19598   0/imm32/read
19599   0xa8/imm32/length
19600   # data
19601   # general-purpose registers
19602   # it is perfectly ok to use fake alloc-ids -- as long as you never try to reclaim them
19603   0x11/imm32/alloc-id $Mu-register-eax/imm32 0/imm32
19604   0x11/imm32/alloc-id $Mu-register-ecx/imm32 1/imm32
19605   0x11/imm32/alloc-id $Mu-register-edx/imm32 2/imm32
19606   0x11/imm32/alloc-id $Mu-register-ebx/imm32 3/imm32
19607   0x11/imm32/alloc-id $Mu-register-esi/imm32 6/imm32
19608   0x11/imm32/alloc-id $Mu-register-edi/imm32 7/imm32
19609   # floating-point registers
19610   0x11/imm32/alloc-id $Mu-register-xmm0/imm32 0/imm32
19611   0x11/imm32/alloc-id $Mu-register-xmm1/imm32 1/imm32
19612   0x11/imm32/alloc-id $Mu-register-xmm2/imm32 2/imm32
19613   0x11/imm32/alloc-id $Mu-register-xmm3/imm32 3/imm32
19614   0x11/imm32/alloc-id $Mu-register-xmm4/imm32 4/imm32
19615   0x11/imm32/alloc-id $Mu-register-xmm5/imm32 5/imm32
19616   0x11/imm32/alloc-id $Mu-register-xmm6/imm32 6/imm32
19617   0x11/imm32/alloc-id $Mu-register-xmm7/imm32 7/imm32
19619 # Like Mu-registers, but with unique codes for integer and floating-point
19620 # registers.
19621 # Don't use this for code-generation, only for checking.
19622 Mu-registers-unique:  # (addr stream {(handle array byte), int})
19623   # a table is a stream
19624   0xa8/imm32/write
19625   0/imm32/read
19626   0xa8/imm32/length
19627   # data
19628   # general-purpose registers
19629   0x11/imm32/alloc-id $Mu-register-eax/imm32 0/imm32
19630   0x11/imm32/alloc-id $Mu-register-ecx/imm32 1/imm32
19631   0x11/imm32/alloc-id $Mu-register-edx/imm32 2/imm32
19632   0x11/imm32/alloc-id $Mu-register-ebx/imm32 3/imm32
19633   0x11/imm32/alloc-id $Mu-register-esi/imm32 6/imm32
19634   0x11/imm32/alloc-id $Mu-register-edi/imm32 7/imm32
19635   # floating-point registers
19636   0x11/imm32/alloc-id $Mu-register-xmm0/imm32 8/imm32
19637   0x11/imm32/alloc-id $Mu-register-xmm1/imm32 9/imm32
19638   0x11/imm32/alloc-id $Mu-register-xmm2/imm32 0xa/imm32
19639   0x11/imm32/alloc-id $Mu-register-xmm3/imm32 0xb/imm32
19640   0x11/imm32/alloc-id $Mu-register-xmm4/imm32 0xc/imm32
19641   0x11/imm32/alloc-id $Mu-register-xmm5/imm32 0xd/imm32
19642   0x11/imm32/alloc-id $Mu-register-xmm6/imm32 0xe/imm32
19643   0x11/imm32/alloc-id $Mu-register-xmm7/imm32 0xf/imm32
19645 $Mu-register-eax:
19646   0x11/imm32/alloc-id
19647   3/imm32/size
19648   0x65/e 0x61/a 0x78/x
19650 $Mu-register-ecx:
19651   0x11/imm32/alloc-id
19652   3/imm32/size
19653   0x65/e 0x63/c 0x78/x
19655 $Mu-register-edx:
19656   0x11/imm32/alloc-id
19657   3/imm32/size
19658   0x65/e 0x64/d 0x78/x
19660 $Mu-register-ebx:
19661   0x11/imm32/alloc-id
19662   3/imm32/size
19663   0x65/e 0x62/b 0x78/x
19665 $Mu-register-esi:
19666   0x11/imm32/alloc-id
19667   3/imm32/size
19668   0x65/e 0x73/s 0x69/i
19670 $Mu-register-edi:
19671   0x11/imm32/alloc-id
19672   3/imm32/size
19673   0x65/e 0x64/d 0x69/i
19675 $Mu-register-xmm0:
19676   0x11/imm32/alloc-id:fake:payload
19677   # "xmm0"
19678   0x4/imm32/size
19679   0x78/x 0x6d/m 0x6d/m 0x30/0
19681 $Mu-register-xmm1:
19682   0x11/imm32/alloc-id:fake:payload
19683   # "xmm1"
19684   0x4/imm32/size
19685   0x78/x 0x6d/m 0x6d/m 0x31/1
19687 $Mu-register-xmm2:
19688   0x11/imm32/alloc-id:fake:payload
19689   # "xmm2"
19690   0x4/imm32/size
19691   0x78/x 0x6d/m 0x6d/m 0x32/2
19693 $Mu-register-xmm3:
19694   0x11/imm32/alloc-id:fake:payload
19695   # "xmm3"
19696   0x4/imm32/size
19697   0x78/x 0x6d/m 0x6d/m 0x33/3
19699 $Mu-register-xmm4:
19700   0x11/imm32/alloc-id:fake:payload
19701   # "xmm4"
19702   0x4/imm32/size
19703   0x78/x 0x6d/m 0x6d/m 0x34/4
19705 $Mu-register-xmm5:
19706   0x11/imm32/alloc-id:fake:payload
19707   # "xmm5"
19708   0x4/imm32/size
19709   0x78/x 0x6d/m 0x6d/m 0x35/5
19711 $Mu-register-xmm6:
19712   0x11/imm32/alloc-id:fake:payload
19713   # "xmm6"
19714   0x4/imm32/size
19715   0x78/x 0x6d/m 0x6d/m 0x36/6
19717 $Mu-register-xmm7:
19718   0x11/imm32/alloc-id:fake:payload
19719   # "xmm7"
19720   0x4/imm32/size
19721   0x78/x 0x6d/m 0x6d/m 0x37/7
19723 == code
19725 # push 'out' to 'vars' if not already there; it's assumed to be a fn output
19726 maybe-define-var:  # out: (handle var), vars: (addr stack live-var)
19727     # . prologue
19728     55/push-ebp
19729     89/<- %ebp 4/r32/esp
19730     # . save registers
19731     50/push-eax
19732     # var out-addr/eax: (addr var)
19733     (lookup *(ebp+8) *(ebp+0xc))  # => eax
19734     #
19735     (binding-exists? %eax *(ebp+0x10))  # => eax
19736     3d/compare-eax-and 0/imm32/false
19737     75/jump-if-!= $maybe-define-var:end/disp8
19738     # otherwise update vars
19739     (push *(ebp+0x10) *(ebp+8))
19740     (push *(ebp+0x10) *(ebp+0xc))
19741     (push *(ebp+0x10) 0)  # 'out' is always a fn output; never spill it
19742 $maybe-define-var:end:
19743     # . restore registers
19744     58/pop-to-eax
19745     # . epilogue
19746     89/<- %esp 5/r32/ebp
19747     5d/pop-to-ebp
19748     c3/return
19750 # simpler version of lookup-var-helper
19751 binding-exists?:  # target: (addr var), vars: (addr stack live-var) -> result/eax: boolean
19752     # pseudocode:
19753     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
19754     #   var min = vars->data
19755     #   while curr >= min
19756     #     var v: (handle var) = *curr
19757     #     if v->name == target->name
19758     #       return true
19759     #     curr -= 12
19760     #   return false
19761     #
19762     # . prologue
19763     55/push-ebp
19764     89/<- %ebp 4/r32/esp
19765     # . save registers
19766     51/push-ecx
19767     52/push-edx
19768     56/push-esi
19769     # var target-name/ecx: (addr array byte) = lookup(target->name)
19770     8b/-> *(ebp+8) 0/r32/eax
19771     (lookup *eax *(eax+4))  # Var-name Var-name => eax
19772     89/<- %ecx 0/r32/eax
19773     # esi = vars
19774     8b/-> *(ebp+0xc) 6/r32/esi
19775     # eax = vars->top
19776     8b/-> *esi 0/r32/eax
19777     # var min/edx: (addr handle var) = vars->data
19778     8d/copy-address *(esi+8) 2/r32/edx
19779     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
19780     8d/copy-address *(esi+eax-4) 6/r32/esi  # vars + 8 + vars->type - 12
19781     {
19782 $binding-exists?:loop:
19783       # if (curr < min) return
19784       39/compare %esi 2/r32/edx
19785       0f 82/jump-if-addr< break/disp32
19786       # var v/eax: (addr var) = lookup(*curr)
19787       (lookup *esi *(esi+4))  # => eax
19788       # var vn/eax: (addr array byte) = lookup(v->name)
19789       (lookup *eax *(eax+4))  # Var-name Var-name => eax
19790       # if (vn == target-name) return true
19791       (string-equal? %ecx %eax)  # => eax
19792       3d/compare-eax-and 0/imm32/false
19793       75/jump-if-!= $binding-exists?:end/disp8  # eax already contains true
19794       # curr -= 12
19795       81 5/subop/subtract %esi 0xc/imm32
19796       e9/jump loop/disp32
19797     }
19798     b8/copy-to-eax 0/imm32/false
19799 $binding-exists?:end:
19800     # . restore registers
19801     5e/pop-to-esi
19802     5a/pop-to-edx
19803     59/pop-to-ecx
19804     # . epilogue
19805     89/<- %esp 5/r32/ebp
19806     5d/pop-to-ebp
19807     c3/return
19809 test-parse-mu-stmt:
19810     # . prologue
19811     55/push-ebp
19812     89/<- %ebp 4/r32/esp
19813     # setup
19814     8b/-> *Primitive-type-ids 0/r32/eax
19815     89/<- *Type-id 0/r32/eax  # stream-write
19816     (clear-stream _test-input-stream)
19817     (write _test-input-stream "increment n\n")
19818     # var vars/ecx: (stack (addr var) 16)
19819     81 5/subop/subtract %esp 0xc0/imm32
19820     68/push 0xc0/imm32/size
19821     68/push 0/imm32/top
19822     89/<- %ecx 4/r32/esp
19823     (clear-stack %ecx)
19824     # var v/edx: (handle var)
19825     68/push 0/imm32
19826     68/push 0/imm32
19827     89/<- %edx 4/r32/esp
19828     # var s/eax: (handle array byte)
19829     68/push 0/imm32
19830     68/push 0/imm32
19831     89/<- %eax 4/r32/esp
19832     # v = new var("n")
19833     (copy-array Heap "n" %eax)
19834     (new-var Heap *eax *(eax+4) %edx)
19835     #
19836     (push %ecx *edx)
19837     (push %ecx *(edx+4))
19838     (push %ecx 0)
19839     # var out/eax: (handle stmt)
19840     68/push 0/imm32
19841     68/push 0/imm32
19842     89/<- %eax 4/r32/esp
19843     # convert
19844     (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
19845     # var out-addr/edx: (addr stmt) = lookup(*out)
19846     (lookup *eax *(eax+4))  # => eax
19847     89/<- %edx 0/r32/eax
19848     # out->tag
19849     (check-ints-equal *edx 1 "F - test-parse-mu-stmt/tag")  # Stmt-tag is Stmt1
19850     # out->operation
19851     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
19852     (check-strings-equal %eax "increment" "F - test-parse-mu-stmt/name")  # Stmt1-operation
19853     # out->inouts->value->name
19854     # . eax = out->inouts
19855     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
19856     # . eax = out->inouts->value
19857     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
19858     # . eax = out->inouts->value->name
19859     (lookup *eax *(eax+4))  # Var-name Var-name => eax
19860     # .
19861     (check-strings-equal %eax "n" "F - test-parse-mu-stmt/inout:0")
19862     # . epilogue
19863     89/<- %esp 5/r32/ebp
19864     5d/pop-to-ebp
19865     c3/return
19867 test-parse-mu-stmt-with-comma:
19868     # . prologue
19869     55/push-ebp
19870     89/<- %ebp 4/r32/esp
19871     # setup
19872     8b/-> *Primitive-type-ids 0/r32/eax
19873     89/<- *Type-id 0/r32/eax  # stream-write
19874     (clear-stream _test-input-stream)
19875     (write _test-input-stream "copy-to n, 3\n")
19876     # var vars/ecx: (stack (addr var) 16)
19877     81 5/subop/subtract %esp 0xc0/imm32
19878     68/push 0xc0/imm32/size
19879     68/push 0/imm32/top
19880     89/<- %ecx 4/r32/esp
19881     (clear-stack %ecx)
19882     # var v/edx: (handle var)
19883     68/push 0/imm32
19884     68/push 0/imm32
19885     89/<- %edx 4/r32/esp
19886     # var s/eax: (handle array byte)
19887     68/push 0/imm32
19888     68/push 0/imm32
19889     89/<- %eax 4/r32/esp
19890     # v = new var("n")
19891     (copy-array Heap "n" %eax)
19892     (new-var Heap *eax *(eax+4) %edx)
19893     #
19894     (push %ecx *edx)
19895     (push %ecx *(edx+4))
19896     (push %ecx 0)
19897     # var out/eax: (handle stmt)
19898     68/push 0/imm32
19899     68/push 0/imm32
19900     89/<- %eax 4/r32/esp
19901     # convert
19902     (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
19903     # var out-addr/edx: (addr stmt) = lookup(*out)
19904     (lookup *eax *(eax+4))  # => eax
19905     89/<- %edx 0/r32/eax
19906     # out->tag
19907     (check-ints-equal *edx 1 "F - test-parse-mu-stmt-with-comma/tag")  # Stmt-tag is Stmt1
19908     # out->operation
19909     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
19910     (check-strings-equal %eax "copy-to" "F - test-parse-mu-stmt-with-comma/name")  # Stmt1-operation
19911     # out->inouts->value->name
19912     # . eax = out->inouts
19913     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
19914     # . eax = out->inouts->value
19915     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
19916     # . eax = out->inouts->value->name
19917     (lookup *eax *(eax+4))  # Var-name Var-name => eax
19918     # .
19919     (check-strings-equal %eax "n" "F - test-parse-mu-stmt-with-comma/inout:0")
19920     # . epilogue
19921     89/<- %esp 5/r32/ebp
19922     5d/pop-to-ebp
19923     c3/return
19925 new-var:  # ad: (addr allocation-descriptor), name: (handle array byte), out: (addr handle var)
19926     # . prologue
19927     55/push-ebp
19928     89/<- %ebp 4/r32/esp
19929     # . save registers
19930     50/push-eax
19931     51/push-ecx
19932     # ecx = out
19933     8b/-> *(ebp+0x14) 1/r32/ecx
19934     #
19935     (allocate *(ebp+8) *Var-size %ecx)
19936     # var out-addr/eax: (addr var)
19937     (lookup *ecx *(ecx+4))  # => eax
19938     # out-addr->name = name
19939     8b/-> *(ebp+0xc) 1/r32/ecx
19940     89/<- *eax 1/r32/ecx  # Var-name
19941     8b/-> *(ebp+0x10) 1/r32/ecx
19942     89/<- *(eax+4) 1/r32/ecx  # Var-name
19943 #?     (write-buffered Stderr "var ")
19944 #?     (lookup *(ebp+0xc) *(ebp+0x10))
19945 #?     (write-buffered Stderr %eax)
19946 #?     (write-buffered Stderr " at ")
19947 #?     8b/-> *(ebp+0x14) 1/r32/ecx
19948 #?     (lookup *ecx *(ecx+4))  # => eax
19949 #?     (write-int32-hex-buffered Stderr %eax)
19950 #?     (write-buffered Stderr Newline)
19951 #?     (flush Stderr)
19952 $new-var:end:
19953     # . restore registers
19954     59/pop-to-ecx
19955     58/pop-to-eax
19956     # . epilogue
19957     89/<- %esp 5/r32/ebp
19958     5d/pop-to-ebp
19959     c3/return
19961 # WARNING: modifies name
19962 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)
19963     # . prologue
19964     55/push-ebp
19965     89/<- %ebp 4/r32/esp
19966     # . save registers
19967     50/push-eax
19968     51/push-ecx
19969     # first strip out metadata
19970     8b/-> *(ebp+0xc) 1/r32/ecx
19971     (next-token-from-slice *ecx *(ecx+4) 0x2f *(ebp+0xc))
19972     # if (!is-hex-int?(name)) abort
19973     (hex-int? *(ebp+0xc))  # => eax
19974     3d/compare-eax-and 0/imm32/false
19975     0f 84/jump-if-= $new-literal-integer:abort/disp32
19976     # a little more error-checking
19977     (check-mu-hex-int *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c))
19978     # out = new var(s)
19979     (new-var-from-slice *(ebp+8) *(ebp+0xc) *(ebp+0x10))
19980     # var out-addr/ecx: (addr var) = lookup(*out)
19981     8b/-> *(ebp+0x10) 0/r32/eax
19982     (lookup *eax *(eax+4))  # => eax
19983     89/<- %ecx 0/r32/eax
19984     # out-addr->block-depth = *Curr-block-depth
19985     8b/-> *Curr-block-depth 0/r32/eax
19986     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
19987     # out-addr->type = new tree()
19988     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
19989     (allocate *(ebp+8) *Type-tree-size %eax)
19990     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
19991     c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
19992     # nothing else to do; default type is 'literal'
19993 $new-literal-integer:end:
19994     # . reclaim locals
19995     81 0/subop/add %esp 8/imm32
19996     # . restore registers
19997     59/pop-to-ecx
19998     58/pop-to-eax
19999     # . epilogue
20000     89/<- %esp 5/r32/ebp
20001     5d/pop-to-ebp
20002     c3/return
20004 $new-literal-integer:abort:
20005     (write-buffered *(ebp+0x18) "fn ")
20006     8b/-> *(ebp+0x14) 0/r32/eax
20007     (lookup *eax *(eax+4))  # Function-name Function-name => eax
20008     (write-buffered *(ebp+0x18) %eax)
20009     (write-buffered *(ebp+0x18) ": variable '")
20010     (write-slice-buffered *(ebp+0x18) *(ebp+0xc))
20011     (write-buffered *(ebp+0x18) "' cannot begin with a digit (or do you have a typo in a number?)\n")
20012     (flush *(ebp+0x18))
20013     (stop *(ebp+0x1c) 1)
20014     # never gets here
20016 # precondition: name is a valid hex integer; require a '0x' prefix
20017 check-mu-hex-int:  # name: (addr slice), err: (addr buffered-file), ed: (addr exit-descriptor)
20018     # . prologue
20019     55/push-ebp
20020     89/<- %ebp 4/r32/esp
20021     # . save registers
20022     50/push-eax
20023     51/push-ecx
20024     52/push-edx
20025     # ecx = name
20026     8b/-> *(ebp+8) 1/r32/ecx
20027     # var start/edx: (addr byte) = name->start
20028     8b/-> *ecx 2/r32/edx
20029     # if (*start == '-') ++start
20030     b8/copy-to-eax 0/imm32
20031     8a/copy-byte *edx 0/r32/AL
20032     3d/compare-eax-and 0x2d/imm32/dash
20033     {
20034       75/jump-if-!= break/disp8
20035       42/increment-edx
20036     }
20037     # var end/ecx: (addr byte) = name->end
20038     8b/-> *(ecx+4) 1/r32/ecx
20039     # var len/eax: int = name->end - name->start
20040     89/<- %eax 1/r32/ecx
20041     29/subtract-from %eax 2/r32/edx
20042     # if (len <= 1) return
20043     3d/compare-eax-with 1/imm32
20044     0f 8e/jump-if-<= $check-mu-hex-int:end/disp32
20045 $check-mu-hex-int:length->-1:
20046     # if slice-starts-with?({start, end}, "0x") return
20047     # . var tmp = {start, end}
20048     51/push-ecx
20049     52/push-edx
20050     89/<- %eax 4/r32/esp
20051     # .
20052     (slice-starts-with? %eax "0x")  # => eax
20053     # . reclaim tmp
20054     81 0/subop/add %esp 8/imm32
20055     # .
20056     3d/compare-eax-with 0/imm32/false
20057     75/jump-if-!= $check-mu-hex-int:end/disp8
20058 $check-mu-hex-int:abort:
20059     # otherwise abort
20060     (write-buffered *(ebp+0xc) "literal integers are always hex in Mu; start '")
20061     (write-slice-buffered *(ebp+0xc) *(ebp+8))
20062     (write-buffered *(ebp+0xc) "' with a '0x' to be unambiguous, converting it to hexadecimal as necessary.\n")
20063     (flush *(ebp+0xc))
20064     (stop *(ebp+0x10) 1)
20065 $check-mu-hex-int:end:
20066     # . restore registers
20067     5a/pop-to-edx
20068     59/pop-to-ecx
20069     58/pop-to-eax
20070     # . epilogue
20071     89/<- %esp 5/r32/ebp
20072     5d/pop-to-ebp
20073     c3/return
20075 new-literal:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
20076     # . prologue
20077     55/push-ebp
20078     89/<- %ebp 4/r32/esp
20079     # . save registers
20080     50/push-eax
20081     51/push-ecx
20082     # var s/ecx: (handle array byte)
20083     68/push 0/imm32
20084     68/push 0/imm32
20085     89/<- %ecx 4/r32/esp
20086     # s = slice-to-string(name)
20087     (slice-to-string Heap *(ebp+0xc) %ecx)
20088     # allocate to out
20089     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
20090     # var out-addr/ecx: (addr var) = lookup(*out)
20091     8b/-> *(ebp+0x10) 1/r32/ecx
20092     (lookup *ecx *(ecx+4))  # => eax
20093     89/<- %ecx 0/r32/eax
20094     # out-addr->block-depth = *Curr-block-depth
20095     8b/-> *Curr-block-depth 0/r32/eax
20096     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
20097     # out-addr->type/eax = new type
20098     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
20099     (allocate *(ebp+8) *Type-tree-size %eax)
20100     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
20101     # nothing else to do; default type is 'literal'
20102     c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
20103 $new-literal:end:
20104     # . reclaim locals
20105     81 0/subop/add %esp 8/imm32
20106     # . restore registers
20107     59/pop-to-ecx
20108     58/pop-to-eax
20109     # . epilogue
20110     89/<- %esp 5/r32/ebp
20111     5d/pop-to-ebp
20112     c3/return
20114 new-literal-string:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
20115     # . prologue
20116     55/push-ebp
20117     89/<- %ebp 4/r32/esp
20118     # . save registers
20119     50/push-eax
20120     51/push-ecx
20121     # var s/ecx: (handle array byte)
20122     68/push 0/imm32
20123     68/push 0/imm32
20124     89/<- %ecx 4/r32/esp
20125     # s = slice-to-string(name)
20126     (slice-to-string Heap *(ebp+0xc) %ecx)
20127     # allocate to out
20128     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
20129     # var out-addr/ecx: (addr var) = lookup(*out)
20130     8b/-> *(ebp+0x10) 1/r32/ecx
20131     (lookup *ecx *(ecx+4))  # => eax
20132     89/<- %ecx 0/r32/eax
20133     # out-addr->block-depth = *Curr-block-depth
20134     8b/-> *Curr-block-depth 0/r32/eax
20135     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
20136     # out-addr->type/eax = new type
20137     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
20138     (allocate *(ebp+8) *Type-tree-size %eax)
20139     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
20140     # out-addr->type->value = literal-string
20141     c7 0/subop/copy *(eax+4) 0x10/imm32/type-id-string-literal  # Type-tree-value
20142     # out-addr->type->is-atom? = true
20143     c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
20144 $new-literal-string:end:
20145     # . reclaim locals
20146     81 0/subop/add %esp 8/imm32
20147     # . restore registers
20148     59/pop-to-ecx
20149     58/pop-to-eax
20150     # . epilogue
20151     89/<- %esp 5/r32/ebp
20152     5d/pop-to-ebp
20153     c3/return
20155 new-var-from-slice:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
20156     # . prologue
20157     55/push-ebp
20158     89/<- %ebp 4/r32/esp
20159     # . save registers
20160     51/push-ecx
20161     # var tmp/ecx: (handle array byte)
20162     68/push 0/imm32
20163     68/push 0/imm32
20164     89/<- %ecx 4/r32/esp
20165     # tmp = slice-to-string(name)
20166     (slice-to-string Heap *(ebp+0xc) %ecx)
20167     # out = new-var(tmp)
20168     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
20169 $new-var-from-slice:end:
20170     # . reclaim locals
20171     81 0/subop/add %esp 8/imm32
20172     # . restore registers
20173     59/pop-to-ecx
20174     # . epilogue
20175     89/<- %esp 5/r32/ebp
20176     5d/pop-to-ebp
20177     c3/return
20179 new-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
20180     # . prologue
20181     55/push-ebp
20182     89/<- %ebp 4/r32/esp
20183     # . save registers
20184     50/push-eax
20185     51/push-ecx
20186     #
20187     (allocate *(ebp+8) *Stmt-size *(ebp+0x14))
20188     # var out-addr/eax: (addr stmt) = lookup(*out)
20189     8b/-> *(ebp+0x14) 0/r32/eax
20190     (lookup *eax *(eax+4))  # => eax
20191     # out-addr->tag = stmt
20192     c7 0/subop/copy *eax 2/imm32/tag/var-on-stack  # Stmt-tag
20193     # result->var = var
20194     8b/-> *(ebp+0xc) 1/r32/ecx
20195     89/<- *(eax+4) 1/r32/ecx  # Vardef-var
20196     8b/-> *(ebp+0x10) 1/r32/ecx
20197     89/<- *(eax+8) 1/r32/ecx  # Vardef-var
20198 $new-var-def:end:
20199     # . restore registers
20200     59/pop-to-ecx
20201     58/pop-to-eax
20202     # . epilogue
20203     89/<- %esp 5/r32/ebp
20204     5d/pop-to-ebp
20205     c3/return
20207 new-reg-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
20208     # . prologue
20209     55/push-ebp
20210     89/<- %ebp 4/r32/esp
20211     # . save registers
20212     50/push-eax
20213     # eax = out
20214     8b/-> *(ebp+0x14) 0/r32/eax
20215     #
20216     (allocate *(ebp+8) *Stmt-size %eax)
20217     # var out-addr/eax: (addr stmt) = lookup(*out)
20218     (lookup *eax *(eax+4))  # => eax
20219     # set tag
20220     c7 0/subop/copy *eax 3/imm32/tag/var-in-register  # Stmt-tag
20221     # set output
20222     8d/copy-address *(eax+0x14) 0/r32/eax  # Regvardef-outputs
20223     (append-stmt-var Heap  *(ebp+0xc) *(ebp+0x10)  0 0  0  %eax)
20224 $new-reg-var-def:end:
20225     # . restore registers
20226     58/pop-to-eax
20227     # . epilogue
20228     89/<- %esp 5/r32/ebp
20229     5d/pop-to-ebp
20230     c3/return
20232 append-list:  # ad: (addr allocation-descriptor), value: (handle _type), list: (handle list _type), out: (addr handle list _type)
20233     # . prologue
20234     55/push-ebp
20235     89/<- %ebp 4/r32/esp
20236     # . save registers
20237     50/push-eax
20238     51/push-ecx
20239     57/push-edi
20240     # edi = out
20241     8b/-> *(ebp+0x1c) 7/r32/edi
20242     # *out = new list
20243     (allocate *(ebp+8) *List-size %edi)
20244     # var out-addr/edi: (addr list _type) = lookup(*out)
20245     (lookup *edi *(edi+4))  # => eax
20246     89/<- %edi 0/r32/eax
20247     # out-addr->value = value
20248     8b/-> *(ebp+0xc) 0/r32/eax
20249     89/<- *edi 0/r32/eax  # List-value
20250     8b/-> *(ebp+0x10) 0/r32/eax
20251     89/<- *(edi+4) 0/r32/eax  # List-value
20252     # if (list == null) return
20253     81 7/subop/compare *(ebp+0x14) 0/imm32
20254     74/jump-if-= $append-list:end/disp8
20255     # otherwise append
20256 $append-list:non-empty-list:
20257     # var curr/eax: (addr list _type) = lookup(list)
20258     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
20259     # while (curr->next != null) curr = curr->next
20260     {
20261       81 7/subop/compare *(eax+8) 0/imm32  # List-next
20262       74/jump-if-= break/disp8
20263       # curr = lookup(curr->next)
20264       (lookup *(eax+8) *(eax+0xc))  # List-next, List-next => eax
20265       #
20266       eb/jump loop/disp8
20267     }
20268     # edi = out
20269     8b/-> *(ebp+0x1c) 7/r32/edi
20270     # curr->next = out
20271     8b/-> *edi 1/r32/ecx
20272     89/<- *(eax+8) 1/r32/ecx  # List-next
20273     8b/-> *(edi+4) 1/r32/ecx
20274     89/<- *(eax+0xc) 1/r32/ecx  # List-next
20275     # out = list
20276     8b/-> *(ebp+0x14) 1/r32/ecx
20277     89/<- *edi 1/r32/ecx
20278     8b/-> *(ebp+0x18) 1/r32/ecx
20279     89/<- *(edi+4) 1/r32/ecx
20280 $append-list:end:
20281     # . restore registers
20282     5f/pop-to-edi
20283     59/pop-to-ecx
20284     58/pop-to-eax
20285     # . epilogue
20286     89/<- %esp 5/r32/ebp
20287     5d/pop-to-ebp
20288     c3/return
20290 append-stmt-var:  # ad: (addr allocation-descriptor), v: (handle var), vars: (handle stmt-var), is-deref?: boolean, out: (addr handle stmt-var)
20291     # . prologue
20292     55/push-ebp
20293     89/<- %ebp 4/r32/esp
20294     # . save registers
20295     50/push-eax
20296     51/push-ecx
20297     57/push-edi
20298     # edi = out
20299     8b/-> *(ebp+0x20) 7/r32/edi
20300     # out = new stmt-var
20301     (allocate *(ebp+8) *Stmt-var-size %edi)
20302     # var out-addr/ecx: (addr stmt-var) = lookup(*out)
20303     (lookup *edi *(edi+4))  # => eax
20304     89/<- %ecx 0/r32/eax
20305     # out-addr->value = v
20306     8b/-> *(ebp+0xc) 0/r32/eax
20307     89/<- *ecx 0/r32/eax  # Stmt-var-value
20308     8b/-> *(ebp+0x10) 0/r32/eax
20309     89/<- *(ecx+4) 0/r32/eax  # Stmt-var-value
20310     # out-addr->is-deref? = is-deref?
20311     8b/-> *(ebp+0x1c) 0/r32/eax
20312     89/<- *(ecx+0x10) 0/r32/eax  # Stmt-var-is-deref
20313     # if (vars == null) return result
20314     81 7/subop/compare *(ebp+0x14) 0/imm32/null
20315     74/jump-if-= $append-stmt-var:end/disp8
20316     # otherwise append
20317     # var curr/eax: (addr stmt-var) = lookup(vars)
20318     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
20319     # while (curr->next != null) curr = curr->next
20320     {
20321       81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
20322       74/jump-if-= break/disp8
20323       # curr = lookup(curr->next)
20324       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next, Stmt-var-next => eax
20325       #
20326       eb/jump loop/disp8
20327     }
20328     # curr->next = out
20329     8b/-> *edi 1/r32/ecx
20330     89/<- *(eax+8) 1/r32/ecx  # Stmt-var-next
20331     8b/-> *(edi+4) 1/r32/ecx
20332     89/<- *(eax+0xc) 1/r32/ecx  # Stmt-var-next
20333     # out = vars
20334     8b/-> *(ebp+0x14) 1/r32/ecx
20335     89/<- *edi 1/r32/ecx
20336     8b/-> *(ebp+0x18) 1/r32/ecx
20337     89/<- *(edi+4) 1/r32/ecx
20338 $append-stmt-var:end:
20339     # . restore registers
20340     5f/pop-to-edi
20341     59/pop-to-ecx
20342     58/pop-to-eax
20343     # . epilogue
20344     89/<- %esp 5/r32/ebp
20345     5d/pop-to-ebp
20346     c3/return
20348 append-to-block:  # ad: (addr allocation-descriptor), block: (addr block), x: (handle stmt)
20349     # . prologue
20350     55/push-ebp
20351     89/<- %ebp 4/r32/esp
20352     # . save registers
20353     50/push-eax
20354     56/push-esi
20355     # esi = block
20356     8b/-> *(ebp+0xc) 6/r32/esi
20357     # block->stmts = append(x, block->stmts)
20358     8d/copy-address *(esi+4) 0/r32/eax  # Block-stmts
20359     (append-list *(ebp+8)  *(ebp+0x10) *(ebp+0x14)  *(esi+4) *(esi+8)  %eax)  # ad, x, x, Block-stmts, Block-stmts
20360 $append-to-block:end:
20361     # . restore registers
20362     5e/pop-to-esi
20363     58/pop-to-eax
20364     # . epilogue
20365     89/<- %esp 5/r32/ebp
20366     5d/pop-to-ebp
20367     c3/return
20369 ## Parsing types
20370 # We need to create metadata on user-defined types, and we need to use this
20371 # metadata as we parse instructions.
20372 # However, we also want to allow types to be used before their definitions.
20373 # This means we can't ever assume any type data structures exist.
20375 lookup-or-create-constant:  # container: (addr stmt-var), field-name: (addr slice), out: (addr handle var)
20376     # . prologue
20377     55/push-ebp
20378     89/<- %ebp 4/r32/esp
20379     # . save registers
20380     50/push-eax
20381     56/push-esi
20382     # var container-type/esi: type-id
20383     (container-type *(ebp+8))  # => eax
20384     89/<- %esi 0/r32/eax
20385     # var tmp/eax: (handle typeinfo) = find-or-create-typeinfo(container-type)
20386     68/push 0/imm32
20387     68/push 0/imm32
20388     89/<- %eax 4/r32/esp
20389     (find-or-create-typeinfo %esi %eax)
20390     # var tmp-addr/eax: (addr typeinfo) = lookup(tmp)
20391     (lookup *eax *(eax+4))  # => eax
20392     # result = find-or-create-typeinfo-output-var(typeinfo, field-name)
20393 #?     (write-buffered Stderr "constant: ")
20394 #?     (write-slice-buffered Stderr *(ebp+0xc))
20395 #?     (write-buffered Stderr Newline)
20396 #?     (flush Stderr)
20397     (find-or-create-typeinfo-output-var %eax *(ebp+0xc) *(ebp+0x10))
20398 #?     8b/-> *(ebp+0x10) 0/r32/eax
20399 #?     (write-buffered Stderr "@")
20400 #?     (lookup *eax *(eax+4))
20401 #?     (write-int32-hex-buffered Stderr %eax)
20402 #?     (lookup *eax *(eax+4))
20403 #?     (write-buffered Stderr %eax)
20404 #?     (write-buffered Stderr Newline)
20405 #?     (flush Stderr)
20406 #?     (write-buffered Stderr "offset: ")
20407 #?     8b/-> *(eax+0x14) 0/r32/eax
20408 #?     (write-int32-hex-buffered Stderr %eax)
20409 #?     (write-buffered Stderr Newline)
20410 #?     (flush Stderr)
20411 $lookup-or-create-constant:end:
20412     # . reclaim locals
20413     81 0/subop/add %esp 8/imm32
20414     # . restore registers
20415     5e/pop-to-esi
20416     58/pop-to-eax
20417     # . epilogue
20418     89/<- %esp 5/r32/ebp
20419     5d/pop-to-ebp
20420     c3/return
20422 # if addr var:
20423 #   container->var->type->right->left->value
20424 # otherwise
20425 #   container->var->type->value
20426 container-type:  # container: (addr stmt-var) -> result/eax: type-id
20427     # . prologue
20428     55/push-ebp
20429     89/<- %ebp 4/r32/esp
20430     #
20431     8b/-> *(ebp+8) 0/r32/eax
20432     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
20433     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
20434     {
20435       81 7/subop/compare *(eax+8) 0/imm32  # Type-tree-right
20436       74/jump-if-= break/disp8
20437       (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
20438       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
20439     }
20440     8b/-> *(eax+4) 0/r32/eax  # Type-tree-value
20441 $container-type:end:
20442     # . epilogue
20443     89/<- %esp 5/r32/ebp
20444     5d/pop-to-ebp
20445     c3/return
20447 container?:  # t: type-id -> result/eax: boolean
20448     # . prologue
20449     55/push-ebp
20450     89/<- %ebp 4/r32/esp
20451     #
20452     8b/-> *(ebp+8) 0/r32/eax
20453     c1/shift 4/subop/left %eax 2/imm8
20454     3b/compare 0/r32/eax *Primitive-type-ids
20455     0f 9d/set-if->= %al
20456     25/and-eax-with 0xff/imm32
20457 $container?:end:
20458     # . epilogue
20459     89/<- %esp 5/r32/ebp
20460     5d/pop-to-ebp
20461     c3/return
20463 find-or-create-typeinfo:  # t: type-id, out: (addr handle typeinfo)
20464     # . prologue
20465     55/push-ebp
20466     89/<- %ebp 4/r32/esp
20467     # . save registers
20468     50/push-eax
20469     51/push-ecx
20470     52/push-edx
20471     57/push-edi
20472     # edi = out
20473     8b/-> *(ebp+0xc) 7/r32/edi
20474     # var fields/ecx: (handle table (handle array byte) (handle typeinfo-entry))
20475     68/push 0/imm32
20476     68/push 0/imm32
20477     89/<- %ecx 4/r32/esp
20478     # find-typeinfo(t, out)
20479     (find-typeinfo *(ebp+8) %edi)
20480     {
20481       # if (*out != 0) break
20482       81 7/subop/compare *edi 0/imm32
20483       0f 85/jump-if-!= break/disp32
20484 $find-or-create-typeinfo:create:
20485       # *out = allocate
20486       (allocate Heap *Typeinfo-size %edi)
20487       # var tmp/eax: (addr typeinfo) = lookup(*out)
20488       (lookup *edi *(edi+4))  # => eax
20489 #?     (write-buffered Stderr "created typeinfo at ")
20490 #?     (write-int32-hex-buffered Stderr %eax)
20491 #?     (write-buffered Stderr " for type-id ")
20492 #?     (write-int32-hex-buffered Stderr *(ebp+8))
20493 #?     (write-buffered Stderr Newline)
20494 #?     (flush Stderr)
20495       # tmp->id = t
20496       8b/-> *(ebp+8) 2/r32/edx
20497       89/<- *eax 2/r32/edx  # Typeinfo-id
20498       # tmp->fields = new table
20499       # . fields = new table
20500       (new-stream Heap 0x40 *Typeinfo-fields-row-size %ecx)
20501       # . tmp->fields = fields
20502       8b/-> *ecx 2/r32/edx
20503       89/<- *(eax+4) 2/r32/edx  # Typeinfo-fields
20504       8b/-> *(ecx+4) 2/r32/edx
20505       89/<- *(eax+8) 2/r32/edx  # Typeinfo-fields
20506       # tmp->next = Program->types
20507       8b/-> *_Program-types 1/r32/ecx
20508       89/<- *(eax+0x10) 1/r32/ecx  # Typeinfo-next
20509       8b/-> *_Program-types->payload 1/r32/ecx
20510       89/<- *(eax+0x14) 1/r32/ecx  # Typeinfo-next
20511       # Program->types = out
20512       8b/-> *edi 1/r32/ecx
20513       89/<- *_Program-types 1/r32/ecx
20514       8b/-> *(edi+4) 1/r32/ecx
20515       89/<- *_Program-types->payload 1/r32/ecx
20516     }
20517 $find-or-create-typeinfo:end:
20518     # . reclaim locals
20519     81 0/subop/add %esp 8/imm32
20520     # . restore registers
20521     5f/pop-to-edi
20522     5a/pop-to-edx
20523     59/pop-to-ecx
20524     58/pop-to-eax
20525     # . epilogue
20526     89/<- %esp 5/r32/ebp
20527     5d/pop-to-ebp
20528     c3/return
20530 find-typeinfo:  # t: type-id, out: (addr handle typeinfo)
20531     # . prologue
20532     55/push-ebp
20533     89/<- %ebp 4/r32/esp
20534     # . save registers
20535     50/push-eax
20536     51/push-ecx
20537     52/push-edx
20538     57/push-edi
20539     # ecx = t
20540     8b/-> *(ebp+8) 1/r32/ecx
20541     # edi = out
20542     8b/-> *(ebp+0xc) 7/r32/edi
20543     # *out = Program->types
20544     8b/-> *_Program-types 0/r32/eax
20545     89/<- *edi 0/r32/eax
20546     8b/-> *_Program-types->payload 0/r32/eax
20547     89/<- *(edi+4) 0/r32/eax
20548     {
20549 $find-typeinfo:loop:
20550       # if (*out == 0) break
20551       81 7/subop/compare *edi 0/imm32
20552       74/jump-if-= break/disp8
20553 $find-typeinfo:check:
20554       # var tmp/eax: (addr typeinfo) = lookup(*out)
20555       (lookup *edi *(edi+4))  # => eax
20556       # if (tmp->id == t) break
20557       39/compare *eax 1/r32/ecx  # Typeinfo-id
20558       74/jump-if-= break/disp8
20559 $find-typeinfo:continue:
20560       # *out = tmp->next
20561       8b/-> *(eax+0x10) 2/r32/edx  # Typeinfo-next
20562       89/<- *edi 2/r32/edx
20563       8b/-> *(eax+0x14) 2/r32/edx  # Typeinfo-next
20564       89/<- *(edi+4) 2/r32/edx
20565       #
20566       eb/jump loop/disp8
20567     }
20568 $find-typeinfo:end:
20569     # . restore registers
20570     5f/pop-to-edi
20571     5a/pop-to-edx
20572     59/pop-to-ecx
20573     58/pop-to-eax
20574     # . epilogue
20575     89/<- %esp 5/r32/ebp
20576     5d/pop-to-ebp
20577     c3/return
20579 find-or-create-typeinfo-output-var:  # T: (addr typeinfo), f: (addr slice), out: (addr handle var)
20580     # . prologue
20581     55/push-ebp
20582     89/<- %ebp 4/r32/esp
20583     # . save registers
20584     50/push-eax
20585     52/push-edx
20586     57/push-edi
20587     # var dest/edi: (handle typeinfo-entry)
20588     68/push 0/imm32
20589     68/push 0/imm32
20590     89/<- %edi 4/r32/esp
20591     # find-or-create-typeinfo-fields(T, f, dest)
20592     (find-or-create-typeinfo-fields *(ebp+8) *(ebp+0xc) %edi)
20593     # var dest-addr/edi: (addr typeinfo-entry) = lookup(dest)
20594     (lookup *edi *(edi+4))  # => eax
20595     89/<- %edi 0/r32/eax
20596     # if dest-addr->output-var doesn't exist, create it
20597     {
20598       81 7/subop/compare *(edi+0xc) 0/imm32  # Typeinfo-entry-output-var
20599       0f 85/jump-if-!= break/disp32
20600       # dest-addr->output-var = new var(dummy name, type, -1 offset)
20601       # . var name/eax: (handle array byte) = "field"
20602       68/push 0/imm32
20603       68/push 0/imm32
20604       89/<- %eax 4/r32/esp
20605       (slice-to-string Heap *(ebp+0xc) %eax)
20606       # . new var
20607       8d/copy-address *(edi+0xc) 2/r32/edx
20608       (new-var Heap  *eax *(eax+4)  %edx)
20609       # . reclaim name
20610       81 0/subop/add %esp 8/imm32
20611       # var result/edx: (addr var) = lookup(dest-addr->output-var)
20612       (lookup *(edi+0xc) *(edi+0x10))  # => eax
20613       89/<- %edx 0/r32/eax
20614       # result->type = new constant type
20615       8d/copy-address *(edx+8) 0/r32/eax  # Var-type
20616       (allocate Heap *Type-tree-size %eax)
20617       (lookup *(edx+8) *(edx+0xc))  # => eax
20618       c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
20619       c7 0/subop/copy *(eax+4) 6/imm32/constant  # Type-tree-value
20620       c7 0/subop/copy *(eax+8) 0/imm32  # Type-tree-left
20621       c7 0/subop/copy *(eax+0xc) 0/imm32  # Type-tree-right
20622       c7 0/subop/copy *(eax+0x10) 0/imm32  # Type-tree-right
20623       # result->offset isn't filled out yet
20624       c7 0/subop/copy *(edx+0x14) -1/imm32/uninitialized  # Var-offset
20625     }
20626     # out = dest-addr->output-var
20627     8b/-> *(ebp+0x10) 2/r32/edx
20628     8b/-> *(edi+0xc) 0/r32/eax  # Typeinfo-entry-output-var
20629     89/<- *edx 0/r32/eax
20630     8b/-> *(edi+0x10) 0/r32/eax  # Typeinfo-entry-output-var
20631     89/<- *(edx+4) 0/r32/eax
20632 $find-or-create-typeinfo-output-var:end:
20633     # . reclaim locals
20634     81 0/subop/add %esp 8/imm32
20635     # . restore registers
20636     5f/pop-to-edi
20637     5a/pop-to-edx
20638     58/pop-to-eax
20639     # . epilogue
20640     89/<- %esp 5/r32/ebp
20641     5d/pop-to-ebp
20642     c3/return
20644 find-or-create-typeinfo-fields:  # T: (addr typeinfo), f: (addr slice), out: (addr handle typeinfo-entry)
20645     # . prologue
20646     55/push-ebp
20647     89/<- %ebp 4/r32/esp
20648     # . save registers
20649     50/push-eax
20650     56/push-esi
20651     57/push-edi
20652     # eax = lookup(T->fields)
20653     8b/-> *(ebp+8) 0/r32/eax
20654     (lookup *(eax+4) *(eax+8))  # Typeinfo-fields Typeinfo-fields => eax
20655     # edi = out
20656     8b/-> *(ebp+0x10) 7/r32/edi
20657     # var src/esi: (addr handle typeinfo-entry) = get-or-insert-slice(T->fields, f)
20658     (get-or-insert-slice %eax *(ebp+0xc) *Typeinfo-fields-row-size Heap)  # => eax
20659     89/<- %esi 0/r32/eax
20660     # if src doesn't exist, allocate it
20661     {
20662       81 7/subop/compare *esi 0/imm32
20663       75/jump-if-!= break/disp8
20664       (allocate Heap *Typeinfo-entry-size %esi)
20665 #?       (write-buffered Stderr "handle at ")
20666 #?       (write-int32-hex-buffered Stderr %esi)
20667 #?       (write-buffered Stderr ": ")
20668 #?       (write-int32-hex-buffered Stderr *esi)
20669 #?       (write-buffered Stderr " ")
20670 #?       (write-int32-hex-buffered Stderr *(esi+4))
20671 #?       (write-buffered Stderr Newline)
20672 #?       (flush Stderr)
20673 #?       (lookup *esi *(esi+4))
20674 #?       (write-buffered Stderr "created typeinfo fields at ")
20675 #?       (write-int32-hex-buffered Stderr %esi)
20676 #?       (write-buffered Stderr " for ")
20677 #?       (write-int32-hex-buffered Stderr *(ebp+8))
20678 #?       (write-buffered Stderr Newline)
20679 #?       (flush Stderr)
20680     }
20681     # *out = src
20682     # . *edi = *src
20683     8b/-> *esi 0/r32/eax
20684     89/<- *edi 0/r32/eax
20685     8b/-> *(esi+4) 0/r32/eax
20686     89/<- *(edi+4) 0/r32/eax
20687 $find-or-create-typeinfo-fields:end:
20688     # . restore registers
20689     5f/pop-to-edi
20690     5e/pop-to-esi
20691     58/pop-to-eax
20692     # . epilogue
20693     89/<- %esp 5/r32/ebp
20694     5d/pop-to-ebp
20695     c3/return
20697 populate-mu-type:  # in: (addr stream byte), t: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
20698     # pseudocode:
20699     #   var line: (stream byte 512)
20700     #   curr-index = 0
20701     #   while true
20702     #     clear-stream(line)
20703     #     read-line-buffered(in, line)
20704     #     if line->write == 0
20705     #       abort
20706     #     word-slice = next-mu-token(line)
20707     #     if slice-empty?(word-slice)               # end of line
20708     #       continue
20709     #     if slice-equal?(word-slice, "}")
20710     #       break
20711     #     var v: (handle var) = parse-var-with-type(word-slice, line)
20712     #     var r: (handle typeinfo-fields) = find-or-create-typeinfo-fields(t, word-slice/v->name)
20713     #     TODO: ensure that r->first is null
20714     #     r->index = curr-index
20715     #     curr-index++
20716     #     r->input-var = v
20717     #     if r->output-var == 0
20718     #       r->output-var = new literal
20719     #     TODO: ensure nothing else in line
20720     # t->total-size-in-bytes = -2 (not yet initialized)
20721     #
20722     # . prologue
20723     55/push-ebp
20724     89/<- %ebp 4/r32/esp
20725     # var curr-index: int at *(ebp-4)
20726     68/push 0/imm32
20727     # . save registers
20728     50/push-eax
20729     51/push-ecx
20730     52/push-edx
20731     53/push-ebx
20732     56/push-esi
20733     57/push-edi
20734     # edi = t
20735     8b/-> *(ebp+0xc) 7/r32/edi
20736     # var line/ecx: (stream byte 512)
20737     81 5/subop/subtract %esp 0x200/imm32
20738     68/push 0x200/imm32/size
20739     68/push 0/imm32/read
20740     68/push 0/imm32/write
20741     89/<- %ecx 4/r32/esp
20742     # var word-slice/edx: slice
20743     68/push 0/imm32/end
20744     68/push 0/imm32/start
20745     89/<- %edx 4/r32/esp
20746     # var v/esi: (handle var)
20747     68/push 0/imm32
20748     68/push 0/imm32
20749     89/<- %esi 4/r32/esp
20750     # var r/ebx: (handle typeinfo-entry)
20751     68/push 0/imm32
20752     68/push 0/imm32
20753     89/<- %ebx 4/r32/esp
20754     {
20755 $populate-mu-type:line-loop:
20756       (clear-stream %ecx)
20757       (read-line-buffered *(ebp+8) %ecx)
20758       # if (line->write == 0) abort
20759       81 7/subop/compare *ecx 0/imm32
20760       0f 84/jump-if-= $populate-mu-type:error1/disp32
20761 #?       # dump line {{{
20762 #?       (write 2 "parse-mu: ^")
20763 #?       (write-stream 2 %ecx)
20764 #?       (write 2 "$\n")
20765 #?       (rewind-stream %ecx)
20766 #?       # }}}
20767       (next-mu-token %ecx %edx)
20768       # if slice-empty?(word-slice) continue
20769       (slice-empty? %edx)  # => eax
20770       3d/compare-eax-and 0/imm32
20771       0f 85/jump-if-!= loop/disp32
20772       # if slice-equal?(word-slice, "}") break
20773       (slice-equal? %edx "}")
20774       3d/compare-eax-and 0/imm32
20775       0f 85/jump-if-!= break/disp32
20776 $populate-mu-type:parse-element:
20777       # v = parse-var-with-type(word-slice, first-line)
20778       # must do this first to strip the trailing ':' from word-slice before
20779       # using it in find-or-create-typeinfo-fields below
20780       # TODO: clean up that mutation in parse-var-with-type
20781       (type-name *edi)  # Typeinfo-id => eax
20782       (parse-var-with-type %edx %ecx %esi %eax *(ebp+0x10) *(ebp+0x14))
20783       # if v is an addr, abort
20784       (lookup *esi *(esi+4))  # => eax
20785       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
20786       (mu-addr-type? %eax)  # => eax
20787       3d/compare-eax-and 0/imm32/false
20788       0f 85/jump-if-!= $populate-mu-type:error2/disp32
20789       # if v is an array, abort  (we could support it, but initialization gets complex)
20790       (lookup *esi *(esi+4))  # => eax
20791       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
20792       (mu-array-type? %eax)  # => eax
20793       3d/compare-eax-and 0/imm32/false
20794       0f 85/jump-if-!= $populate-mu-type:error3/disp32
20795       # if v is a byte, abort
20796       (lookup *esi *(esi+4))  # => eax
20797       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
20798       (simple-mu-type? %eax 8)  # byte => eax
20799       3d/compare-eax-and 0/imm32/false
20800       0f 85/jump-if-!= $populate-mu-type:error4/disp32
20801       # if v is a slice, abort
20802       (lookup *esi *(esi+4))  # => eax
20803       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
20804       (simple-mu-type? %eax 0xc)  # slice => eax
20805       3d/compare-eax-and 0/imm32/false
20806       0f 85/jump-if-!= $populate-mu-type:error5/disp32
20807       # if v is a stream, abort  (we could support it, but initialization gets even more complex)
20808       (lookup *esi *(esi+4))  # => eax
20809       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
20810       (mu-stream-type? %eax)  # => eax
20811       3d/compare-eax-and 0/imm32/false
20812       0f 85/jump-if-!= $populate-mu-type:error6/disp32
20813       # var tmp/ecx
20814       51/push-ecx
20815 $populate-mu-type:create-typeinfo-fields:
20816       # var r/ebx: (handle typeinfo-entry)
20817       (find-or-create-typeinfo-fields %edi %edx %ebx)
20818       # r->index = curr-index
20819       (lookup *ebx *(ebx+4))  # => eax
20820       8b/-> *(ebp-4) 1/r32/ecx
20821 #?       (write-buffered Stderr "saving index ")
20822 #?       (write-int32-hex-buffered Stderr %ecx)
20823 #?       (write-buffered Stderr " at ")
20824 #?       (write-int32-hex-buffered Stderr %edi)
20825 #?       (write-buffered Stderr Newline)
20826 #?       (flush Stderr)
20827       89/<- *(eax+8) 1/r32/ecx  # Typeinfo-entry-index
20828       # ++curr-index
20829       ff 0/subop/increment *(ebp-4)
20830 $populate-mu-type:set-input-type:
20831       # r->input-var = v
20832       8b/-> *esi 1/r32/ecx
20833       89/<- *eax 1/r32/ecx  # Typeinfo-entry-input-var
20834       8b/-> *(esi+4) 1/r32/ecx
20835       89/<- *(eax+4) 1/r32/ecx  # Typeinfo-entry-input-var
20836       # restore line
20837       59/pop-to-ecx
20838       {
20839 $populate-mu-type:create-output-type:
20840         # if (r->output-var == 0) create a new var with some placeholder data
20841         81 7/subop/compare *(eax+0xc) 0/imm32  # Typeinfo-entry-output-var
20842         75/jump-if-!= break/disp8
20843         8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
20844         (new-literal Heap %edx %eax)
20845       }
20846       e9/jump loop/disp32
20847     }
20848 $populate-mu-type:invalidate-total-size-in-bytes:
20849     # Offsets and total size may not be accurate here since we may not yet
20850     # have encountered the element types.
20851     # We'll recompute them separately after parsing the entire program.
20852     c7 0/subop/copy *(edi+0xc) -2/imm32/uninitialized  # Typeinfo-total-size-in-bytes
20853 $populate-mu-type:end:
20854     # . reclaim locals
20855     81 0/subop/add %esp 0x224/imm32
20856     # . restore registers
20857     5f/pop-to-edi
20858     5e/pop-to-esi
20859     5b/pop-to-ebx
20860     5a/pop-to-edx
20861     59/pop-to-ecx
20862     58/pop-to-eax
20863     # reclaim curr-index
20864     81 0/subop/add %esp 4/imm32
20865     # . epilogue
20866     89/<- %esp 5/r32/ebp
20867     5d/pop-to-ebp
20868     c3/return
20870 $populate-mu-type:error1:
20871     # error("incomplete type definition '" t->name "'\n")
20872     (write-buffered *(ebp+0x10) "incomplete type definition '")
20873     (type-name *edi)  # Typeinfo-id => eax
20874     (write-buffered *(ebp+0x10) %eax)
20875     (write-buffered *(ebp+0x10) "\n")
20876     (flush *(ebp+0x10))
20877     (stop *(ebp+0x14) 1)
20878     # never gets here
20880 $populate-mu-type:error2:
20881     (write-buffered *(ebp+0x10) "type ")
20882     (type-name *edi)  # Typeinfo-id => eax
20883     (write-buffered *(ebp+0x10) %eax)
20884     (write-buffered *(ebp+0x10) ": 'addr' elements not allowed\n")
20885     (flush *(ebp+0x10))
20886     (stop *(ebp+0x14) 1)
20887     # never gets here
20889 $populate-mu-type:error3:
20890     (write-buffered *(ebp+0x10) "type ")
20891     (type-name *edi)  # Typeinfo-id => eax
20892     (write-buffered *(ebp+0x10) %eax)
20893     (write-buffered *(ebp+0x10) ": 'array' elements not allowed for now\n")
20894     (flush *(ebp+0x10))
20895     (stop *(ebp+0x14) 1)
20896     # never gets here
20898 $populate-mu-type:error4:
20899     (write-buffered *(ebp+0x10) "type ")
20900     (type-name *edi)  # Typeinfo-id => eax
20901     (write-buffered *(ebp+0x10) %eax)
20902     (write-buffered *(ebp+0x10) ": 'byte' elements not allowed\n")
20903     (flush *(ebp+0x10))
20904     (stop *(ebp+0x14) 1)
20905     # never gets here
20907 $populate-mu-type:error5:
20908     (write-buffered *(ebp+0x10) "type ")
20909     (type-name *edi)  # Typeinfo-id => eax
20910     (write-buffered *(ebp+0x10) %eax)
20911     (write-buffered *(ebp+0x10) ": 'slice' elements not allowed\n")
20912     (flush *(ebp+0x10))
20913     (stop *(ebp+0x14) 1)
20914     # never gets here
20916 $populate-mu-type:error6:
20917     (write-buffered *(ebp+0x10) "type ")
20918     (type-name *edi)  # Typeinfo-id => eax
20919     (write-buffered *(ebp+0x10) %eax)
20920     (write-buffered *(ebp+0x10) ": 'stream' elements not allowed for now\n")
20921     (flush *(ebp+0x10))
20922     (stop *(ebp+0x14) 1)
20923     # never gets here
20925 type-name:  # index: int -> result/eax: (addr array byte)
20926     # . prologue
20927     55/push-ebp
20928     89/<- %ebp 4/r32/esp
20929     #
20930     (index Type-id *(ebp+8))
20931 $type-name:end:
20932     # . epilogue
20933     89/<- %esp 5/r32/ebp
20934     5d/pop-to-ebp
20935     c3/return
20937 index:  # arr: (addr stream (handle array byte)), index: int -> result/eax: (addr array byte)
20938     # . prologue
20939     55/push-ebp
20940     89/<- %ebp 4/r32/esp
20941     # . save registers
20942     56/push-esi
20943     # TODO: bounds-check index
20944     # esi = arr
20945     8b/-> *(ebp+8) 6/r32/esi
20946     # eax = index
20947     8b/-> *(ebp+0xc) 0/r32/eax
20948     # eax = *(arr + 12 + index)
20949     8b/-> *(esi+eax<<2+0xc) 0/r32/eax
20950 $index:end:
20951     # . restore registers
20952     5e/pop-to-esi
20953     # . epilogue
20954     89/<- %esp 5/r32/ebp
20955     5d/pop-to-ebp
20956     c3/return
20958 #######################################################
20959 # Compute type sizes
20960 #######################################################
20962 # Compute the sizes of all user-defined types.
20963 # We'll need the sizes of their elements, which may be other user-defined
20964 # types, which we will compute as needed.
20966 # Initially, all user-defined types have their sizes set to -2 (invalid)
20967 populate-mu-type-sizes:  # err: (addr buffered-file), ed: (addr exit-descriptor)
20968     # . prologue
20969     55/push-ebp
20970     89/<- %ebp 4/r32/esp
20971 $populate-mu-type-sizes:total-sizes:
20972     # var curr/eax: (addr typeinfo) = lookup(Program->types)
20973     (lookup *_Program-types *_Program-types->payload)  # => eax
20974     {
20975       # if (curr == null) break
20976       3d/compare-eax-and 0/imm32/null
20977       74/jump-if-= break/disp8
20978       (populate-mu-type-sizes-in-type %eax *(ebp+8) *(ebp+0xc))
20979       # curr = lookup(curr->next)
20980       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
20981       eb/jump loop/disp8
20982     }
20983 $populate-mu-type-sizes:offsets:
20984     # curr = *Program->types
20985     (lookup *_Program-types *_Program-types->payload)  # => eax
20986     {
20987       # if (curr == null) break
20988       3d/compare-eax-and 0/imm32/null
20989       74/jump-if-= break/disp8
20990       (populate-mu-type-offsets %eax *(ebp+8) *(ebp+0xc))
20991       # curr = curr->next
20992       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
20993       eb/jump loop/disp8
20994     }
20995 $populate-mu-type-sizes:end:
20996     # . epilogue
20997     89/<- %esp 5/r32/ebp
20998     5d/pop-to-ebp
20999     c3/return
21001 # compute sizes of all fields, recursing as necessary
21002 # sum up all their sizes to arrive at total size
21003 # fields may be out of order, but that doesn't affect the answer
21004 populate-mu-type-sizes-in-type:  # T: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
21005     # . prologue
21006     55/push-ebp
21007     89/<- %ebp 4/r32/esp
21008     # . save registers
21009     50/push-eax
21010     51/push-ecx
21011     52/push-edx
21012     56/push-esi
21013     57/push-edi
21014     # esi = T
21015     8b/-> *(ebp+8) 6/r32/esi
21016     # if T is already computed, return
21017     81 7/subop/compare *(esi+0xc) 0/imm32  # Typeinfo-total-size-in-bytes
21018     0f 8d/jump-if->= $populate-mu-type-sizes-in-type:end/disp32
21019     # if T is being computed, abort
21020     81 7/subop/compare *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
21021     0f 84/jump-if-= $populate-mu-type-sizes-in-type:abort/disp32
21022     # tag T (-2 to -1) to avoid infinite recursion
21023     c7 0/subop/copy *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
21024     # var total-size/edi: int = 0
21025     bf/copy-to-edi 0/imm32
21026     # - for every field, if it's a user-defined type, compute its size
21027     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
21028     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
21029     89/<- %ecx 0/r32/eax
21030     # var table-size/edx: int = table->write
21031     8b/-> *ecx 2/r32/edx  # stream-write
21032     # var curr/ecx: (addr table_row) = table->data
21033     8d/copy-address *(ecx+0xc) 1/r32/ecx
21034     # var max/edx: (addr table_row) = table->data + table->write
21035     8d/copy-address *(ecx+edx) 2/r32/edx
21036     {
21037 $populate-mu-type-sizes-in-type:loop:
21038       # if (curr >= max) break
21039       39/compare %ecx 2/r32/edx
21040       73/jump-if-addr>= break/disp8
21041       # var t/eax: (addr typeinfo-entry) = lookup(curr->value)
21042       (lookup *(ecx+8) *(ecx+0xc))  # => eax
21043       # if (t->input-var == 0) silently ignore it; we'll emit a nice error message while type-checking
21044       81 7/subop/compare *eax 0/imm32  # Typeinfo-entry-input-var
21045       74/jump-if-= $populate-mu-type-sizes-in-type:end/disp8
21046       # compute size of t->input-var
21047       (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
21048       (compute-size-of-var %eax *(ebp+0xc) *(ebp+0x10))  # => eax
21049       # result += eax
21050       01/add-to %edi 0/r32/eax
21051       # curr += row-size
21052       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
21053       #
21054       eb/jump loop/disp8
21055     }
21056     # - save result
21057     89/<- *(esi+0xc) 7/r32/edi  # Typeinfo-total-size-in-bytes
21058 $populate-mu-type-sizes-in-type:end:
21059     # . restore registers
21060     5f/pop-to-edi
21061     5e/pop-to-esi
21062     5a/pop-to-edx
21063     59/pop-to-ecx
21064     58/pop-to-eax
21065     # . epilogue
21066     89/<- %esp 5/r32/ebp
21067     5d/pop-to-ebp
21068     c3/return
21070 $populate-mu-type-sizes-in-type:abort:
21071     (write-buffered *(ebp+0xc) "cycle in type definitions\n")
21072     (flush *(ebp+0xc))
21073     (stop *(ebp+0x10) 1)
21074     # never gets here
21076 # Analogous to size-of, except we need to compute what size-of can just read
21077 # off the right data structures.
21078 compute-size-of-var:  # in: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
21079     # . prologue
21080     55/push-ebp
21081     89/<- %ebp 4/r32/esp
21082     # . push registers
21083     51/push-ecx
21084     # var t/ecx: (addr type-tree) = lookup(v->type)
21085     8b/-> *(ebp+8) 1/r32/ecx
21086     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
21087     89/<- %ecx 0/r32/eax
21088     # if (t->is-atom == false) t = lookup(t->left)
21089     {
21090       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
21091       75/jump-if-!= break/disp8
21092       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
21093       89/<- %ecx 0/r32/eax
21094     }
21095     # TODO: ensure t is an atom
21096     (compute-size-of-type-id *(ecx+4) *(ebp+0xc) *(ebp+0x10))  # Type-tree-value => eax
21097 $compute-size-of-var:end:
21098     # . restore registers
21099     59/pop-to-ecx
21100     # . epilogue
21101     89/<- %esp 5/r32/ebp
21102     5d/pop-to-ebp
21103     c3/return
21105 compute-size-of-type-id:  # t: type-id, err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
21106     # . prologue
21107     55/push-ebp
21108     89/<- %ebp 4/r32/esp
21109     # . save registers
21110     51/push-ecx
21111     # var out/ecx: (handle typeinfo)
21112     68/push 0/imm32
21113     68/push 0/imm32
21114     89/<- %ecx 4/r32/esp
21115     # eax = t
21116     8b/-> *(ebp+8) 0/r32/eax
21117     # if t is a literal, return 0
21118     3d/compare-eax-and 0/imm32/literal
21119     0f 84/jump-if-= $compute-size-of-type-id:end/disp32  # eax changes type from type-id to int
21120     # if t is a byte, return 4 (because we don't really support non-multiples of 4)
21121     3d/compare-eax-and 8/imm32/byte
21122     {
21123       75/jump-if-!= break/disp8
21124       b8/copy-to-eax 4/imm32
21125       eb/jump $compute-size-of-type-id:end/disp8
21126     }
21127     # if t is a handle, return 8
21128     3d/compare-eax-and 4/imm32/handle
21129     {
21130       75/jump-if-!= break/disp8
21131       b8/copy-to-eax 8/imm32
21132       eb/jump $compute-size-of-type-id:end/disp8  # eax changes type from type-id to int
21133     }
21134     # if t is a slice, return 8
21135     3d/compare-eax-and 0xc/imm32/slice
21136     {
21137       75/jump-if-!= break/disp8
21138       b8/copy-to-eax 8/imm32
21139       eb/jump $compute-size-of-type-id:end/disp8  # eax changes type from type-id to int
21140     }
21141     # if t is a user-defined type, compute its size
21142     # TODO: support non-atom type
21143     (find-typeinfo %eax %ecx)
21144     {
21145       81 7/subop/compare *ecx 0/imm32
21146       74/jump-if-= break/disp8
21147 $compute-size-of-type-id:user-defined:
21148       (lookup *ecx *(ecx+4))  # => eax
21149       (populate-mu-type-sizes-in-type %eax *(ebp+0xc) *(ebp+0x10))
21150       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
21151       eb/jump $compute-size-of-type-id:end/disp8
21152     }
21153     # otherwise return the word size
21154     b8/copy-to-eax 4/imm32
21155 $compute-size-of-type-id:end:
21156     # . reclaim locals
21157     81 0/subop/add %esp 8/imm32
21158     # . restore registers
21159     59/pop-to-ecx
21160     # . epilogue
21161     89/<- %esp 5/r32/ebp
21162     5d/pop-to-ebp
21163     c3/return
21165 # at this point we have total sizes for all user-defined types
21166 # compute offsets for each element
21167 # complication: fields may be out of order
21168 populate-mu-type-offsets:  # in: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
21169     # . prologue
21170     55/push-ebp
21171     89/<- %ebp 4/r32/esp
21172     # . save registers
21173     50/push-eax
21174     51/push-ecx
21175     52/push-edx
21176     53/push-ebx
21177     56/push-esi
21178     57/push-edi
21179 #?     (dump-typeinfos "aaa\n")
21180     # var curr-offset/edi: int = 0
21181     bf/copy-to-edi 0/imm32
21182     # var table/ecx: (addr table string_key (handle typeinfo-entry)) = lookup(in->fields)
21183     8b/-> *(ebp+8) 1/r32/ecx
21184     (lookup *(ecx+4) *(ecx+8))  # Typeinfo-fields Typeinfo-fields => eax
21185     89/<- %ecx 0/r32/eax
21186     # var num-elems/edx: int = table->write / Typeinfo-fields-row-size
21187     8b/-> *ecx 2/r32/edx  # stream-write
21188     c1 5/subop/shift-right-logical  %edx 4/imm8
21189     # var i/ebx: int = 0
21190     bb/copy-to-ebx 0/imm32
21191     {
21192 $populate-mu-type-offsets:loop:
21193       39/compare %ebx 2/r32/edx
21194       0f 8d/jump-if->= break/disp32
21195 #?       (write-buffered Stderr "looking up index ")
21196 #?       (write-int32-hex-buffered Stderr %ebx)
21197 #?       (write-buffered Stderr " in ")
21198 #?       (write-int32-hex-buffered Stderr *(ebp+8))
21199 #?       (write-buffered Stderr Newline)
21200 #?       (flush Stderr)
21201       # var v/esi: (addr typeinfo-entry)
21202       (locate-typeinfo-entry-with-index %ecx %ebx *(ebp+0xc) *(ebp+0x10))  # => eax
21203       89/<- %esi 0/r32/eax
21204       # if v is null, silently move on; we'll emit a nice error message while type-checking
21205       81 7/subop/compare %esi 0/imm32  # Typeinfo-entry-input-var
21206       74/jump-if-= $populate-mu-type-offsets:end/disp8
21207       # if (v->input-var == 0) silently ignore v; we'll emit a nice error message while type-checking
21208       81 7/subop/compare *esi 0/imm32  # Typeinfo-entry-input-var
21209       74/jump-if-= $populate-mu-type-offsets:end/disp8
21210       # v->output-var->offset = curr-offset
21211       # . eax: (addr var)
21212       (lookup *(esi+0xc) *(esi+0x10))  # Typeinfo-entry-output-var Typeinfo-entry-output-var => eax
21213       89/<- *(eax+0x14) 7/r32/edi  # Var-offset
21214       # curr-offset += size-of(v->input-var)
21215       (lookup *esi *(esi+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
21216       (size-of %eax)  # => eax
21217       01/add-to %edi 0/r32/eax
21218       # ++i
21219       43/increment-ebx
21220       e9/jump loop/disp32
21221     }
21222 $populate-mu-type-offsets:end:
21223     # . restore registers
21224     5f/pop-to-edi
21225     5e/pop-to-esi
21226     5b/pop-to-ebx
21227     5a/pop-to-edx
21228     59/pop-to-ecx
21229     58/pop-to-eax
21230     # . epilogue
21231     89/<- %esp 5/r32/ebp
21232     5d/pop-to-ebp
21233     c3/return
21235 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)
21236     # . prologue
21237     55/push-ebp
21238     89/<- %ebp 4/r32/esp
21239     # . save registers
21240     51/push-ecx
21241     52/push-edx
21242     53/push-ebx
21243     56/push-esi
21244     57/push-edi
21245     # esi = table
21246     8b/-> *(ebp+8) 6/r32/esi
21247     # var curr/ecx: (addr row (handle array byte) (handle typeinfo-entry)) = table->data
21248     8d/copy-address *(esi+0xc) 1/r32/ecx
21249     # var max/edx: (addr byte) = &table->data[table->write]
21250     8b/-> *esi 2/r32/edx
21251     8d/copy-address *(ecx+edx) 2/r32/edx
21252     {
21253 $locate-typeinfo-entry-with-index:loop:
21254       39/compare %ecx 2/r32/edx
21255       73/jump-if-addr>= break/disp8
21256       # var v/eax: (addr typeinfo-entry)
21257       (lookup *(ecx+8) *(ecx+0xc))  # => eax
21258       # if (v->index == idx) return v
21259       8b/-> *(eax+8) 3/r32/ebx  # Typeinfo-entry-index
21260 #?       (write-buffered Stderr "comparing ")
21261 #?       (write-int32-hex-buffered Stderr %ebx)
21262 #?       (write-buffered Stderr " and ")
21263 #?       (write-int32-hex-buffered Stderr *(ebp+0xc))
21264 #?       (write-buffered Stderr Newline)
21265 #?       (flush Stderr)
21266       39/compare *(ebp+0xc) 3/r32/ebx
21267       74/jump-if-= $locate-typeinfo-entry-with-index:end/disp8
21268       # curr += Typeinfo-entry-size
21269       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-entry-size
21270       #
21271       eb/jump loop/disp8
21272     }
21273     # return 0
21274     b8/copy-to-eax 0/imm32
21275 $locate-typeinfo-entry-with-index:end:
21276 #?     (write-buffered Stderr "returning ")
21277 #?     (write-int32-hex-buffered Stderr %eax)
21278 #?     (write-buffered Stderr Newline)
21279 #?     (flush Stderr)
21280     # . restore registers
21281     5f/pop-to-edi
21282     5e/pop-to-esi
21283     5b/pop-to-ebx
21284     5a/pop-to-edx
21285     59/pop-to-ecx
21286     # . epilogue
21287     89/<- %esp 5/r32/ebp
21288     5d/pop-to-ebp
21289     c3/return
21291 dump-typeinfos:  # hdr: (addr array byte)
21292     # . prologue
21293     55/push-ebp
21294     89/<- %ebp 4/r32/esp
21295     # . save registers
21296     50/push-eax
21297     #
21298     (write-buffered Stderr *(ebp+8))
21299     (flush Stderr)
21300     # var curr/eax: (addr typeinfo) = lookup(Program->types)
21301     (lookup *_Program-types *_Program-types->payload)  # => eax
21302     {
21303       # if (curr == null) break
21304       3d/compare-eax-and 0/imm32
21305       74/jump-if-= break/disp8
21306       (write-buffered Stderr "---\n")
21307       (flush Stderr)
21308       (dump-typeinfo %eax)
21309       # curr = lookup(curr->next)
21310       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
21311       eb/jump loop/disp8
21312     }
21313 $dump-typeinfos:end:
21314     # . restore registers
21315     58/pop-to-eax
21316     # . epilogue
21317     89/<- %esp 5/r32/ebp
21318     5d/pop-to-ebp
21319     c3/return
21321 dump-typeinfo:  # in: (addr typeinfo)
21322     # . prologue
21323     55/push-ebp
21324     89/<- %ebp 4/r32/esp
21325     # . save registers
21326     50/push-eax
21327     51/push-ecx
21328     52/push-edx
21329     53/push-ebx
21330     56/push-esi
21331     57/push-edi
21332     # esi = in
21333     8b/-> *(ebp+8) 6/r32/esi
21334     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
21335     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
21336     89/<- %ecx 0/r32/eax
21337     (write-buffered Stderr "id:")
21338     (write-int32-hex-buffered Stderr *esi)
21339     (write-buffered Stderr "\n")
21340     (write-buffered Stderr "fields @ ")
21341     (write-int32-hex-buffered Stderr %ecx)
21342     (write-buffered Stderr Newline)
21343     (flush Stderr)
21344     (write-buffered Stderr "  write: ")
21345     (write-int32-hex-buffered Stderr *ecx)
21346     (write-buffered Stderr Newline)
21347     (flush Stderr)
21348     (write-buffered Stderr "  read: ")
21349     (write-int32-hex-buffered Stderr *(ecx+4))
21350     (write-buffered Stderr Newline)
21351     (flush Stderr)
21352     (write-buffered Stderr "  size: ")
21353     (write-int32-hex-buffered Stderr *(ecx+8))
21354     (write-buffered Stderr Newline)
21355     (flush Stderr)
21356     # var table-size/edx: int = table->write
21357     8b/-> *ecx 2/r32/edx  # stream-write
21358     # var curr/ecx: (addr table_row) = table->data
21359     8d/copy-address *(ecx+0xc) 1/r32/ecx
21360     # var max/edx: (addr table_row) = table->data + table->write
21361     8d/copy-address *(ecx+edx) 2/r32/edx
21362     {
21363 $dump-typeinfo:loop:
21364       # if (curr >= max) break
21365       39/compare %ecx 2/r32/edx
21366       0f 83/jump-if-addr>= break/disp32
21367       (write-buffered Stderr "  row:\n")
21368       (write-buffered Stderr "    key: ")
21369       (write-int32-hex-buffered Stderr *ecx)
21370       (write-buffered Stderr ",")
21371       (write-int32-hex-buffered Stderr *(ecx+4))
21372       (write-buffered Stderr " = '")
21373       (lookup *ecx *(ecx+4))
21374       (write-buffered Stderr %eax)
21375       (write-buffered Stderr "' @ ")
21376       (write-int32-hex-buffered Stderr %eax)
21377       (write-buffered Stderr Newline)
21378       (flush Stderr)
21379       (write-buffered Stderr "    value: ")
21380       (write-int32-hex-buffered Stderr *(ecx+8))
21381       (write-buffered Stderr ",")
21382       (write-int32-hex-buffered Stderr *(ecx+0xc))
21383       (write-buffered Stderr " = typeinfo-entry@")
21384       (lookup *(ecx+8) *(ecx+0xc))
21385       (write-int32-hex-buffered Stderr %eax)
21386       (write-buffered Stderr Newline)
21387       (flush Stderr)
21388       (write-buffered Stderr "        input var@")
21389       (dump-var 5 %eax)
21390       (lookup *(ecx+8) *(ecx+0xc))
21391       (write-buffered Stderr "        index: ")
21392       (write-int32-hex-buffered Stderr *(eax+8))
21393       (write-buffered Stderr Newline)
21394       (flush Stderr)
21395       (write-buffered Stderr "        output var@")
21396       8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
21397       (dump-var 5 %eax)
21398       (flush Stderr)
21399       # curr += row-size
21400       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
21401       #
21402       e9/jump loop/disp32
21403     }
21404 $dump-typeinfo:end:
21405     # . restore registers
21406     5f/pop-to-edi
21407     5e/pop-to-esi
21408     5b/pop-to-ebx
21409     5a/pop-to-edx
21410     59/pop-to-ecx
21411     58/pop-to-eax
21412     # . epilogue
21413     89/<- %esp 5/r32/ebp
21414     5d/pop-to-ebp
21415     c3/return
21417 dump-var:  # indent: int, v: (addr handle var)
21418     # . prologue
21419     55/push-ebp
21420     89/<- %ebp 4/r32/esp
21421     # . save registers
21422     50/push-eax
21423     53/push-ebx
21424     # eax = v
21425     8b/-> *(ebp+0xc) 0/r32/eax
21426     #
21427     (write-int32-hex-buffered Stderr *eax)
21428     (write-buffered Stderr ",")
21429     (write-int32-hex-buffered Stderr *(eax+4))
21430     (write-buffered Stderr "->")
21431     (lookup *eax *(eax+4))
21432     (write-int32-hex-buffered Stderr %eax)
21433     (write-buffered Stderr Newline)
21434     (flush Stderr)
21435     {
21436       3d/compare-eax-and 0/imm32
21437       0f 84/jump-if-= break/disp32
21438       (emit-indent Stderr *(ebp+8))
21439       (write-buffered Stderr "name: ")
21440       89/<- %ebx 0/r32/eax
21441       (write-int32-hex-buffered Stderr *ebx)  # Var-name
21442       (write-buffered Stderr ",")
21443       (write-int32-hex-buffered Stderr *(ebx+4))  # Var-name
21444       (write-buffered Stderr "->")
21445       (lookup *ebx *(ebx+4))  # Var-name
21446       (write-int32-hex-buffered Stderr %eax)
21447       {
21448         3d/compare-eax-and 0/imm32
21449         74/jump-if-= break/disp8
21450         (write-buffered Stderr Space)
21451         (write-buffered Stderr %eax)
21452       }
21453       (write-buffered Stderr Newline)
21454       (flush Stderr)
21455       (emit-indent Stderr *(ebp+8))
21456       (write-buffered Stderr "block depth: ")
21457       (write-int32-hex-buffered Stderr *(ebx+0x10))  # Var-block-depth
21458       (write-buffered Stderr Newline)
21459       (flush Stderr)
21460       (emit-indent Stderr *(ebp+8))
21461       (write-buffered Stderr "stack offset: ")
21462       (write-int32-hex-buffered Stderr *(ebx+0x14))  # Var-offset
21463       (write-buffered Stderr Newline)
21464       (flush Stderr)
21465       (emit-indent Stderr *(ebp+8))
21466       (write-buffered Stderr "reg: ")
21467       (write-int32-hex-buffered Stderr *(ebx+0x18))  # Var-register
21468       (write-buffered Stderr ",")
21469       (write-int32-hex-buffered Stderr *(ebx+0x1c))  # Var-register
21470       (write-buffered Stderr "->")
21471       (flush Stderr)
21472       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register
21473       (write-int32-hex-buffered Stderr %eax)
21474       {
21475         3d/compare-eax-and 0/imm32
21476         74/jump-if-= break/disp8
21477         (write-buffered Stderr Space)
21478         (write-buffered Stderr %eax)
21479       }
21480       (write-buffered Stderr Newline)
21481       (flush Stderr)
21482     }
21483 $dump-var:end:
21484     # . restore registers
21485     5b/pop-to-ebx
21486     58/pop-to-eax
21487     # . epilogue
21488     89/<- %esp 5/r32/ebp
21489     5d/pop-to-ebp
21490     c3/return
21492 #######################################################
21493 # Type-checking
21494 #######################################################
21496 check-mu-types:  # err: (addr buffered-file), ed: (addr exit-descriptor)
21497     # . prologue
21498     55/push-ebp
21499     89/<- %ebp 4/r32/esp
21500     # . save registers
21501     50/push-eax
21502     # var curr/eax: (addr function) = lookup(Program->functions)
21503     (lookup *_Program-functions *_Program-functions->payload)  # => eax
21504     {
21505 $check-mu-types:loop:
21506       # if (curr == null) break
21507       3d/compare-eax-and 0/imm32
21508       0f 84/jump-if-= break/disp32
21509 #?       # dump curr->name {{{
21510 #?       50/push-eax
21511 #?       (lookup *eax *(eax+4))  # Function-name Function-name => eax
21512 #?       (write-buffered Stderr %eax)
21513 #?       (write-buffered Stderr Newline)
21514 #?       (flush Stderr)
21515 #?       58/pop-to-eax
21516 #?       # }}}
21517       (check-mu-function %eax *(ebp+8) *(ebp+0xc))
21518       # curr = lookup(curr->next)
21519       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
21520       e9/jump loop/disp32
21521     }
21522 $check-mu-types:end:
21523     # . restore registers
21524     58/pop-to-eax
21525     # . epilogue
21526     89/<- %esp 5/r32/ebp
21527     5d/pop-to-ebp
21528     c3/return
21530 check-mu-function:  # fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
21531     # . prologue
21532     55/push-ebp
21533     89/<- %ebp 4/r32/esp
21534     # . save registers
21535     50/push-eax
21536     56/push-esi
21537     # esi = f
21538     8b/-> *(ebp+8) 6/r32/esi
21539     # outputs
21540     (lookup *(esi+0x10) *(esi+0x14))  # Function-outputs Function-outputs => eax
21541     (check-all-unique-registers %eax %esi *(ebp+0xc) *(ebp+0x10))
21542     # body
21543     (lookup *(esi+0x18) *(esi+0x1c))  # Function-body Function-body => eax
21544     (check-mu-block %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10))
21545     # if function has no outputs, we're done
21546     81 7/subop/compare *(esi+0x10) 0/imm32
21547     74/jump-if-= $check-mu-function:end/disp8
21548     # some final checks on body
21549     (check-final-stmt-is-return %eax %esi *(ebp+0xc) *(ebp+0x10))
21550     (check-no-breaks %eax %esi *(ebp+0xc) *(ebp+0x10))
21551 $check-mu-function:end:
21552     # . restore registers
21553     5e/pop-to-esi
21554     58/pop-to-eax
21555     # . epilogue
21556     89/<- %esp 5/r32/ebp
21557     5d/pop-to-ebp
21558     c3/return
21560 check-mu-block:  # block: (addr block), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
21561     # . prologue
21562     55/push-ebp
21563     89/<- %ebp 4/r32/esp
21564     # . save registers
21565     50/push-eax
21566     # eax = block
21567     8b/-> *(ebp+8) 0/r32/eax
21568     # var stmts/eax: (addr list stmt) = lookup(block->statements)
21569     (lookup *(eax+4) *(eax+8))  # Block-stmts Block-stmts => eax
21570     #
21571     {
21572 $check-mu-block:check-empty:
21573       3d/compare-eax-and 0/imm32
21574       0f 84/jump-if-= break/disp32
21575       # emit block->statements
21576       (check-mu-stmt-list %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21577     }
21578 $check-mu-block:end:
21579     # . restore registers
21580     58/pop-to-eax
21581     # . epilogue
21582     89/<- %esp 5/r32/ebp
21583     5d/pop-to-ebp
21584     c3/return
21586 check-mu-stmt-list:  # stmts: (addr list stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
21587     # . prologue
21588     55/push-ebp
21589     89/<- %ebp 4/r32/esp
21590     # . save registers
21591     50/push-eax
21592     56/push-esi
21593     # esi = stmts
21594     8b/-> *(ebp+8) 6/r32/esi
21595     {
21596 $check-mu-stmt-list:loop:
21597       81 7/subop/compare %esi 0/imm32
21598       0f 84/jump-if-= break/disp32
21599       # var curr-stmt/eax: (addr stmt) = lookup(stmts->value)
21600       (lookup *esi *(esi+4))  # List-value List-value => eax
21601       {
21602 $check-mu-stmt-list:check-for-block:
21603         81 7/subop/compare *eax 0/imm32/block  # Stmt-tag
21604         75/jump-if-!= break/disp8
21605 $check-mu-stmt-list:block:
21606         (check-mu-block %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21607         eb/jump $check-mu-stmt-list:continue/disp8
21608       }
21609       {
21610 $check-mu-stmt-list:check-for-stmt1:
21611         81 7/subop/compare *eax 1/imm32/stmt1  # Stmt-tag
21612         0f 85/jump-if-!= break/disp32
21613 $check-mu-stmt-list:stmt1:
21614         (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21615         eb/jump $check-mu-stmt-list:continue/disp8
21616       }
21617       {
21618 $check-mu-stmt-list:check-for-reg-var-def:
21619         81 7/subop/compare *eax 3/imm32/reg-var-def  # Stmt-tag
21620         0f 85/jump-if-!= break/disp32
21621 $check-mu-stmt-list:reg-var-def:
21622         (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21623         eb/jump $check-mu-stmt-list:continue/disp8
21624       }
21625 $check-mu-stmt-list:continue:
21626       # TODO: raise an error on unrecognized Stmt-tag
21627       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
21628       89/<- %esi 0/r32/eax
21629       e9/jump loop/disp32
21630     }
21631 $check-mu-stmt-list:end:
21632     # . restore registers
21633     5e/pop-to-esi
21634     58/pop-to-eax
21635     # . epilogue
21636     89/<- %esp 5/r32/ebp
21637     5d/pop-to-ebp
21638     c3/return
21640 check-mu-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
21641     # . prologue
21642     55/push-ebp
21643     89/<- %ebp 4/r32/esp
21644     # . save registers
21645     50/push-eax
21646     # - if stmt's operation matches a primitive, check against it
21647     (has-primitive-name? *(ebp+8))  # => eax
21648     3d/compare-eax-and 0/imm32/false
21649     {
21650       74/jump-if-= break/disp8
21651       (check-mu-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21652       e9/jump $check-mu-stmt:end/disp32
21653     }
21654     # - otherwise find a function to check against
21655     # var f/eax: (addr function) = lookup(*Program->functions)
21656     (lookup *_Program-functions *_Program-functions->payload)  # => eax
21657     (find-matching-function %eax *(ebp+8))  # => eax
21658     3d/compare-eax-and 0/imm32
21659     {
21660       74/jump-if-= break/disp8
21661       (check-mu-call *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21662       eb/jump $check-mu-stmt:end/disp8
21663     }
21664     # var f/eax: (addr function) = lookup(*Program->signatures)
21665     (lookup *_Program-signatures *_Program-signatures->payload)  # => eax
21666     (find-matching-function %eax *(ebp+8))  # => eax
21667     3d/compare-eax-and 0/imm32
21668     {
21669       74/jump-if-= break/disp8
21670       (check-mu-call *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21671       eb/jump $check-mu-stmt:end/disp8
21672     }
21673     # - otherwise abort
21674     e9/jump $check-mu-stmt:unknown-call/disp32
21675 $check-mu-stmt:end:
21676     # . restore registers
21677     58/pop-to-eax
21678     # . epilogue
21679     89/<- %esp 5/r32/ebp
21680     5d/pop-to-ebp
21681     c3/return
21683 $check-mu-stmt:unknown-call:
21684     (write-buffered *(ebp+0x10) "unknown function '")
21685     8b/-> *(ebp+8) 0/r32/eax
21686     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
21687     (write-buffered *(ebp+0x10) %eax)
21688     (write-buffered *(ebp+0x10) "'\n")
21689     (flush *(ebp+0x10))
21690     (stop *(ebp+0x14) 1)
21691     # never gets here
21693 has-primitive-name?:  # stmt: (addr stmt) -> result/eax: boolean
21694     # . prologue
21695     55/push-ebp
21696     89/<- %ebp 4/r32/esp
21697     # . save registers
21698     51/push-ecx
21699     56/push-esi
21700     # var name/esi: (addr array byte) = lookup(stmt->operation)
21701     8b/-> *(ebp+8) 6/r32/esi
21702     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
21703     89/<- %esi 0/r32/eax
21704     # if (name == "return") return true
21705     (string-equal? %esi "return")  # => eax
21706     3d/compare-eax-and 0/imm32/false
21707     0f 85/jump-if-!= $has-primitive-name?:end/disp32
21708     # if (name == "get") return true
21709     (string-equal? %esi "get")  # => eax
21710     3d/compare-eax-and 0/imm32/false
21711     0f 85/jump-if-!= $has-primitive-name?:end/disp32
21712     # if (name == "index") return true
21713     (string-equal? %esi "index")  # => eax
21714     3d/compare-eax-and 0/imm32/false
21715     0f 85/jump-if-!= $has-primitive-name?:end/disp32
21716     # if (name == "length") return true
21717     (string-equal? %esi "length")  # => eax
21718     3d/compare-eax-and 0/imm32/false
21719     0f 85/jump-if-!= $has-primitive-name?:end/disp32
21720     # if (name == "compute-offset") return true
21721     (string-equal? %esi "compute-offset")  # => eax
21722     3d/compare-eax-and 0/imm32/false
21723     0f 85/jump-if-!= $has-primitive-name?:end/disp32
21724     # if (name == "copy-object") return true
21725     (string-equal? %esi "copy-object")  # => eax
21726     3d/compare-eax-and 0/imm32/false
21727     0f 85/jump-if-!= $has-primitive-name?:end/disp32
21728     # if (name == "clear-object") return true
21729     (string-equal? %esi "clear-object")  # => eax
21730     3d/compare-eax-and 0/imm32/false
21731     0f 85/jump-if-!= $has-primitive-name?:end/disp32
21732     # if (name == "allocate") return true
21733     (string-equal? %esi "allocate")  # => eax
21734     3d/compare-eax-and 0/imm32/false
21735     0f 85/jump-if-!= $has-primitive-name?:end/disp32
21736     # if (name == "populate") return true
21737     (string-equal? %esi "populate")  # => eax
21738     3d/compare-eax-and 0/imm32/false
21739     0f 85/jump-if-!= $has-primitive-name?:end/disp32
21740     # if (name == "populate-stream") return true
21741     (string-equal? %esi "populate-stream")  # => eax
21742     3d/compare-eax-and 0/imm32/false
21743     0f 85/jump-if-!= $has-primitive-name?:end/disp32
21744     # if (name == "read-from-stream") return true
21745     (string-equal? %esi "read-from-stream")  # => eax
21746     3d/compare-eax-and 0/imm32/false
21747     0f 85/jump-if-!= $has-primitive-name?:end/disp32
21748     # if (name == "write-to-stream") return true
21749     (string-equal? %esi "write-to-stream")  # => eax
21750     3d/compare-eax-and 0/imm32/false
21751     0f 85/jump-if-!= $has-primitive-name?:end/disp32
21752     # var curr/ecx: (addr primitive) = Primitives
21753     b9/copy-to-ecx Primitives/imm32
21754     {
21755 $has-primitive-name?:loop:
21756       # if (curr == null) break
21757       81 7/subop/compare %ecx 0/imm32
21758       74/jump-if-= break/disp8
21759       # if (primitive->name == name) return true
21760       (lookup *ecx *(ecx+4))  # Primitive-name Primitive-name => eax
21761 #?       (write-buffered Stderr %eax)
21762 #?       (write-buffered Stderr Newline)
21763 #?       (flush Stderr)
21764       (string-equal? %esi %eax)  # => eax
21765       3d/compare-eax-and 0/imm32/false
21766       75/jump-if-!= $has-primitive-name?:end/disp8
21767 $has-primitive-name?:next-primitive:
21768       # curr = curr->next
21769       (lookup *(ecx+0x3c) *(ecx+0x40))  # Primitive-next Primitive-next => eax
21770       89/<- %ecx 0/r32/eax
21771       #
21772       e9/jump loop/disp32
21773     }
21774     # return null
21775     b8/copy-to-eax 0/imm32
21776 $has-primitive-name?:end:
21777     # . restore registers
21778     5e/pop-to-esi
21779     59/pop-to-ecx
21780     # . epilogue
21781     89/<- %esp 5/r32/ebp
21782     5d/pop-to-ebp
21783     c3/return
21785 check-mu-primitive:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
21786     # . prologue
21787     55/push-ebp
21788     89/<- %ebp 4/r32/esp
21789     # . save registers
21790     50/push-eax
21791     51/push-ecx
21792     # var op/ecx: (addr array byte) = lookup(stmt->operation)
21793     8b/-> *(ebp+8) 0/r32/eax
21794     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
21795     89/<- %ecx 0/r32/eax
21796     # if (op == "copy") check-mu-copy-stmt
21797     {
21798       (string-equal? %ecx "copy")  # => eax
21799       3d/compare-eax-and 0/imm32/false
21800       74/jump-if-= break/disp8
21801       (check-mu-copy-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21802       e9/jump $check-mu-primitive:end/disp32
21803     }
21804     # if (op == "copy-to") check-mu-copy-to-stmt
21805     {
21806       (string-equal? %ecx "copy-to")  # => eax
21807       3d/compare-eax-and 0/imm32/false
21808       74/jump-if-= break/disp8
21809       (check-mu-copy-to-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21810       e9/jump $check-mu-primitive:end/disp32
21811     }
21812     # if (op == "copy-byte") check-mu-copy-byte-stmt
21813     {
21814       (string-equal? %ecx "copy-byte")  # => eax
21815       3d/compare-eax-and 0/imm32/false
21816       74/jump-if-= break/disp8
21817       (check-mu-copy-byte-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21818       e9/jump $check-mu-primitive:end/disp32
21819     }
21820     # if (op == "copy-byte-to") check-mu-copy-byte-to-stmt
21821     {
21822       (string-equal? %ecx "copy-byte-to")  # => eax
21823       3d/compare-eax-and 0/imm32/false
21824       74/jump-if-= break/disp8
21825       (check-mu-copy-byte-to-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21826       e9/jump $check-mu-primitive:end/disp32
21827     }
21828     # if (op == "compare") check-mu-compare-stmt
21829     {
21830       (string-equal? %ecx "compare")  # => eax
21831       3d/compare-eax-and 0/imm32/false
21832       74/jump-if-= break/disp8
21833       (check-mu-compare-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21834       e9/jump $check-mu-primitive:end/disp32
21835     }
21836     # if (op == "address") check-mu-address-stmt
21837     {
21838       (string-equal? %ecx "address")  # => eax
21839       3d/compare-eax-and 0/imm32/false
21840       74/jump-if-= break/disp8
21841       (check-mu-address-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21842       e9/jump $check-mu-primitive:end/disp32
21843     }
21844     # if (op == "return") check-mu-return-stmt
21845     {
21846       (string-equal? %ecx "return")  # => eax
21847       3d/compare-eax-and 0/imm32/false
21848       74/jump-if-= break/disp8
21849       (check-mu-return-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21850       e9/jump $check-mu-primitive:end/disp32
21851     }
21852     # if (op == "get") check-mu-get-stmt
21853     {
21854       (string-equal? %ecx "get")  # => eax
21855       3d/compare-eax-and 0/imm32/false
21856       74/jump-if-= break/disp8
21857       (check-mu-get-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21858       e9/jump $check-mu-primitive:end/disp32
21859     }
21860     # if (op == "index") check-mu-index-stmt
21861     {
21862       (string-equal? %ecx "index")  # => eax
21863       3d/compare-eax-and 0/imm32/false
21864       74/jump-if-= break/disp8
21865       (check-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21866       e9/jump $check-mu-primitive:end/disp32
21867     }
21868     # if (op == "length") check-mu-length-stmt
21869     {
21870       (string-equal? %ecx "length")  # => eax
21871       3d/compare-eax-and 0/imm32/false
21872       74/jump-if-= break/disp8
21873       (check-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21874       e9/jump $check-mu-primitive:end/disp32
21875     }
21876     # if (op == "compute-offset") check-mu-compute-offset-stmt
21877     {
21878       (string-equal? %ecx "compute-offset")  # => eax
21879       3d/compare-eax-and 0/imm32/false
21880       74/jump-if-= break/disp8
21881       (check-mu-compute-offset-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21882       e9/jump $check-mu-primitive:end/disp32
21883     }
21884     # if (op == "copy-object") check-mu-copy-object-stmt
21885     {
21886       (string-equal? %ecx "copy-object")  # => eax
21887       3d/compare-eax-and 0/imm32/false
21888       74/jump-if-= break/disp8
21889       (check-mu-copy-object-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21890       e9/jump $check-mu-primitive:end/disp32
21891     }
21892     # if (op == "clear-object") check-mu-clear-object-stmt
21893     {
21894       (string-equal? %ecx "clear-object")  # => eax
21895       3d/compare-eax-and 0/imm32/false
21896       74/jump-if-= break/disp8
21897       (check-mu-clear-object-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21898       e9/jump $check-mu-primitive:end/disp32
21899     }
21900     # if (op == "allocate") check-mu-allocate-stmt
21901     {
21902       (string-equal? %ecx "allocate")  # => eax
21903       3d/compare-eax-and 0/imm32/false
21904       74/jump-if-= break/disp8
21905       (check-mu-allocate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21906       e9/jump $check-mu-primitive:end/disp32
21907     }
21908     # if (op == "populate") check-mu-populate-stmt
21909     {
21910       (string-equal? %ecx "populate")  # => eax
21911       3d/compare-eax-and 0/imm32/false
21912       74/jump-if-= break/disp8
21913       (check-mu-populate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21914       e9/jump $check-mu-primitive:end/disp32
21915     }
21916     # if (op == "populate-stream") check-mu-populate-stream-stmt
21917     {
21918       (string-equal? %ecx "populate-stream")  # => eax
21919       3d/compare-eax-and 0/imm32/false
21920       74/jump-if-= break/disp8
21921       (check-mu-populate-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21922       e9/jump $check-mu-primitive:end/disp32
21923     }
21924     # if (op == "read-from-stream") check-mu-read-from-stream-stmt
21925     {
21926       (string-equal? %ecx "read-from-stream")  # => eax
21927       3d/compare-eax-and 0/imm32/false
21928       74/jump-if-= break/disp8
21929       (check-mu-read-from-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21930       e9/jump $check-mu-primitive:end/disp32
21931     }
21932     # if (op == "write-to-stream") check-mu-write-to-stream-stmt
21933     {
21934       (string-equal? %ecx "write-to-stream")  # => eax
21935       3d/compare-eax-and 0/imm32/false
21936       74/jump-if-= break/disp8
21937       (check-mu-write-to-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21938       e9/jump $check-mu-primitive:end/disp32
21939     }
21940     # if (op == "convert") check-mu-convert-stmt
21941     {
21942       (string-equal? %ecx "convert")  # => eax
21943       3d/compare-eax-and 0/imm32/false
21944       74/jump-if-= break/disp8
21945       (check-mu-convert-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21946       e9/jump $check-mu-primitive:end/disp32
21947     }
21948     # otherwise check-numberlike-stmt
21949     (check-mu-numberlike-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21950 $check-mu-primitive:end:
21951     # . restore registers
21952     59/pop-to-ecx
21953     58/pop-to-eax
21954     # . epilogue
21955     89/<- %esp 5/r32/ebp
21956     5d/pop-to-ebp
21957     c3/return
21959 # by default, Mu primitives should only operate on 'number-like' types
21960 check-mu-numberlike-primitive:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
21961     # . prologue
21962     55/push-ebp
21963     89/<- %ebp 4/r32/esp
21964     # . save registers
21965     50/push-eax
21966     51/push-ecx
21967     56/push-esi
21968     # esi = stmt
21969     8b/-> *(ebp+8) 6/r32/esi
21970     # var gas/ecx: int = 2
21971     b9/copy-to-ecx 2/imm32
21972     # - check at most 1 output
21973     # var output/eax: (addr stmt-var) = stmt->outputs
21974     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
21975     {
21976       3d/compare-eax-and 0/imm32
21977       74/jump-if-= break/disp8
21978 $check-mu-numberlike-primitive:output:
21979       (check-mu-numberlike-output %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21980       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
21981       3d/compare-eax-and 0/imm32
21982       0f 85/jump-if-!= $check-mu-numberlike-primitive:error-too-many-outputs/disp32
21983       # check output is in a register
21984       # --gas
21985       49/decrement-ecx
21986     }
21987     # - check first inout
21988     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
21989     {
21990       3d/compare-eax-and 0/imm32
21991       0f 84/jump-if-= $check-mu-numberlike-primitive:end/disp32
21992 $check-mu-numberlike-primitive:first-inout:
21993       (check-mu-numberlike-arg %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
21994       # --gas
21995       49/decrement-ecx
21996     }
21997     # - check second inout
21998     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
21999     {
22000       3d/compare-eax-and 0/imm32
22001       74/jump-if-= $check-mu-numberlike-primitive:end/disp8
22002 $check-mu-numberlike-primitive:second-inout:
22003       # is a second inout allowed?
22004       81 7/subop/compare %ecx 0/imm32
22005       0f 84/jump-if-= $check-mu-numberlike-primitive:error-too-many-inouts/disp32
22006 $check-mu-numberlike-primitive:second-inout-permitted:
22007       (check-mu-numberlike-arg %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
22008     }
22009 $check-mu-numberlike-primitive:third-inout:
22010     # if there's a third arg, raise an error
22011     81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
22012     0f 85/jump-if-!= $check-mu-numberlike-primitive:error-too-many-inouts/disp32
22013 $check-mu-numberlike-primitive:end:
22014     # . restore registers
22015     5e/pop-to-esi
22016     59/pop-to-ecx
22017     58/pop-to-eax
22018     # . epilogue
22019     89/<- %esp 5/r32/ebp
22020     5d/pop-to-ebp
22021     c3/return
22023 $check-mu-numberlike-primitive:error-too-many-inouts:
22024     (write-buffered *(ebp+0x10) "fn ")
22025     8b/-> *(ebp+0xc) 0/r32/eax
22026     (lookup *eax *(eax+4))  # Function-name Function-name => eax
22027     (write-buffered *(ebp+0x10) %eax)
22028     (write-buffered *(ebp+0x10) ": stmt ")
22029     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
22030     (write-buffered *(ebp+0x10) %eax)
22031     (write-buffered *(ebp+0x10) ": too many inouts; most primitives support at most two arguments, across inouts and outputs\n")
22032     (flush *(ebp+0x10))
22033     (stop *(ebp+0x14) 1)
22034     # never gets here
22036 $check-mu-numberlike-primitive:error-too-many-outputs:
22037     (write-buffered *(ebp+0x10) "fn ")
22038     8b/-> *(ebp+0xc) 0/r32/eax
22039     (lookup *eax *(eax+4))  # Function-name Function-name => eax
22040     (write-buffered *(ebp+0x10) %eax)
22041     (write-buffered *(ebp+0x10) ": stmt ")
22042     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
22043     (write-buffered *(ebp+0x10) %eax)
22044     (write-buffered *(ebp+0x10) ": too many outputs; most primitives support at most one output\n")
22045     (flush *(ebp+0x10))
22046     (stop *(ebp+0x14) 1)
22047     # never gets here
22049 check-mu-numberlike-arg:  # v: (addr stmt-var), stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
22050     # . prologue
22051     55/push-ebp
22052     89/<- %ebp 4/r32/esp
22053     # . save registers
22054     50/push-eax
22055     56/push-esi
22056     # var t/esi: (addr type-tree) = lookup(v->value->type)
22057     8b/-> *(ebp+8) 0/r32/eax
22058     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
22059     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
22060     89/<- %esi 0/r32/eax
22061 $check-mu-numberlike-arg:check-literal:
22062     # if t is an int, return
22063     (simple-mu-type? %esi 0)  # literal => eax
22064     3d/compare-eax-and 0/imm32/false
22065     0f 85/jump-if-!= $check-mu-numberlike-arg:end/disp32
22066 $check-mu-numberlike-arg:check-addr:
22067     # if t is an addr and v is dereferenced, return whether t->payload is an addr
22068     {
22069       (mu-addr-type? %esi)  # => eax
22070       3d/compare-eax-and 0/imm32/false
22071       74/jump-if-= break/disp8
22072       8b/-> *(ebp+8) 0/r32/eax
22073       8b/-> *(eax+0x10) 0/r32/eax  # Stmt-var-is-deref
22074       3d/compare-eax-and 0/imm32/false
22075       {
22076         74/jump-if-= break/disp8
22077         (lookup *(esi+0xc) *(esi+0x10))  # Type-tree-right Type-tree-right => eax
22078         # if t->right is null, t = t->left
22079         81 7/subop/compare *(eax+0xc) 0/imm32  # Type-tree-right
22080         {
22081           75/jump-if-!= break/disp8
22082           (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
22083         }
22084         (mu-addr-type? %eax)  # => eax
22085         3d/compare-eax-and 0/imm32/false
22086         74/jump-if-= $check-mu-numberlike-arg:end/disp8
22087       }
22088     }
22089 $check-mu-numberlike-arg:output-checks:
22090     (check-mu-numberlike-output *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18))
22091 $check-mu-numberlike-arg:end:
22092     # . restore registers
22093     5e/pop-to-esi
22094     58/pop-to-eax
22095     # . epilogue
22096     89/<- %esp 5/r32/ebp
22097     5d/pop-to-ebp
22098     c3/return
22100 check-mu-numberlike-output:  # v: (addr stmt-var), stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
22101     # . prologue
22102     55/push-ebp
22103     89/<- %ebp 4/r32/esp
22104     # . save registers
22105     50/push-eax
22106     #
22107     (mu-numberlike-output-var? *(ebp+8))  # => eax
22108     3d/compare-eax-and 0/imm32/false
22109     0f 84/jump-if-= $check-mu-numberlike-output:fail/disp32
22110 $check-mu-numberlike-output:end:
22111     # . restore registers
22112     58/pop-to-eax
22113     # . epilogue
22114     89/<- %esp 5/r32/ebp
22115     5d/pop-to-ebp
22116     c3/return
22118 $check-mu-numberlike-output:fail:
22119     # otherwise raise an error
22120     (write-buffered *(ebp+0x14) "fn ")
22121     8b/-> *(ebp+0x10) 0/r32/eax
22122     (lookup *eax *(eax+4))  # Function-name Function-name => eax
22123     (write-buffered *(ebp+0x14) %eax)
22124     (write-buffered *(ebp+0x14) ": stmt ")
22125     8b/-> *(ebp+0xc) 0/r32/eax
22126     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
22127     (write-buffered *(ebp+0x14) %eax)
22128     (write-buffered *(ebp+0x14) ": '")
22129     8b/-> *(ebp+8) 0/r32/eax
22130     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
22131     (lookup *eax *(eax+4))  # Var-name Var-name => eax
22132     (write-buffered *(ebp+0x14) %eax)
22133     (write-buffered *(ebp+0x14) "' must be a non-addr non-offset scalar\n")
22134     (flush *(ebp+0x14))
22135     (stop *(ebp+0x18) 1)
22136     # never gets here
22138 mu-numberlike-output-var?:  # v: (addr stmt-var) -> result/eax: boolean
22139     # . prologue
22140     55/push-ebp
22141     89/<- %ebp 4/r32/esp
22142     #
22143     8b/-> *(ebp+8) 0/r32/eax
22144     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
22145     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
22146     (mu-numberlike-output? %eax)  # => eax
22147 $mu-numberlike-output-var?:end:
22148     # . epilogue
22149     89/<- %esp 5/r32/ebp
22150     5d/pop-to-ebp
22151     c3/return
22153 mu-numberlike-output?:  # v: (addr type-tree) -> result/eax: boolean
22154     # . prologue
22155     55/push-ebp
22156     89/<- %ebp 4/r32/esp
22157     # . save registers
22158     56/push-esi
22159     # var t/esi: (addr type-tree) = lookup(v->value->type)
22160     8b/-> *(ebp+8) 6/r32/esi
22161 $mu-numberlike-output?:check-int:
22162     # if t is an int, return
22163     (simple-mu-type? %esi 1)  # int => eax
22164     3d/compare-eax-and 0/imm32/false
22165     0f 85/jump-if-!= $mu-numberlike-output?:return-true/disp32
22166 $mu-numberlike-output?:check-float:
22167     # if t is a float, return
22168     (simple-mu-type? %esi 0xf)  # float => eax
22169     3d/compare-eax-and 0/imm32/false
22170     75/jump-if-!= $mu-numberlike-output?:return-true/disp8
22171 $mu-numberlike-output?:check-boolean:
22172     # if t is a boolean, return
22173     (simple-mu-type? %esi 5)  # boolean => eax
22174     3d/compare-eax-and 0/imm32/false
22175     75/jump-if-!= $mu-numberlike-output?:return-true/disp8
22176 $mu-numberlike-output?:check-byte:
22177     # if t is a byte, return
22178     (simple-mu-type? %esi 8)  # byte => eax
22179     3d/compare-eax-and 0/imm32/false
22180     75/jump-if-!= $mu-numberlike-output?:return-true/disp8
22181 $mu-numberlike-output?:check-code-point:
22182     # if t is a code-point, return
22183     (simple-mu-type? %esi 0xd)  # code-point => eax
22184     3d/compare-eax-and 0/imm32/false
22185     75/jump-if-!= $mu-numberlike-output?:return-true/disp8
22186 $mu-numberlike-output?:check-grapheme:
22187     # if t is a grapheme, return
22188     (simple-mu-type? %esi 0xe)  # grapheme => eax
22189     3d/compare-eax-and 0/imm32/false
22190     75/jump-if-!= $mu-numberlike-output?:return-true/disp8
22191 $mu-numberlike-output?:return-false:
22192     b8/copy-to-eax 0/imm32/false
22193     eb/jump $mu-numberlike-output?:end/disp8
22194 $mu-numberlike-output?:return-true:
22195     b8/copy-to-eax 1/imm32/true
22196 $mu-numberlike-output?:end:
22197     # . restore registers
22198     5e/pop-to-esi
22199     # . epilogue
22200     89/<- %esp 5/r32/ebp
22201     5d/pop-to-ebp
22202     c3/return
22204 check-mu-copy-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
22205     # . prologue
22206     55/push-ebp
22207     89/<- %ebp 4/r32/esp
22208     # . save registers
22209     50/push-eax
22210     51/push-ecx
22211     52/push-edx
22212     56/push-esi
22213     57/push-edi
22214     # var type-parameters/edx: (addr table (handle array byte) (addr type-tree) 8)
22215     81 5/subop/subtract %esp 0x60/imm32
22216     68/push 0x60/imm32/size
22217     68/push 0/imm32/read
22218     68/push 0/imm32/write
22219     89/<- %edx 4/r32/esp
22220 $check-mu-copy-stmt:get-output:
22221     # esi = stmt
22222     8b/-> *(ebp+8) 6/r32/esi
22223     # var output/edi: (addr stmt-var) = stmt->outputs
22224     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
22225     89/<- %edi 0/r32/eax
22226     # zero outputs
22227     3d/compare-eax-and 0/imm32
22228     0f 84/jump-if-= $check-mu-copy-stmt:error-no-output/disp32
22229     # > 1 output
22230     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
22231     3d/compare-eax-and 0/imm32
22232     0f 85/jump-if-!= $check-mu-copy-stmt:error-too-many-outputs/disp32
22233 $check-mu-copy-stmt:get-inout:
22234     # var inout/esi: (addr stmt-var) = stmt->inouts
22235     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
22236     89/<- %esi 0/r32/eax
22237     # zero inouts
22238     3d/compare-eax-and 0/imm32
22239     0f 84/jump-if-= $check-mu-copy-stmt:error-no-inout/disp32
22240     # > 1 inout
22241     (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
22242     3d/compare-eax-and 0/imm32
22243     0f 85/jump-if-!= $check-mu-copy-stmt:error-too-many-inouts/disp32
22244 $check-mu-copy-stmt:types:
22245     # if inout is not a scalar, abort
22246     (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
22247     (size-of %eax)  # => eax
22248     3d/compare-eax-and 4/imm32
22249     0f 8f/jump-if-> $check-mu-copy-stmt:error-inout-too-large/disp32
22250     # var inout-type/ecx: (addr type-tree) = inout->value->type
22251     (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
22252     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
22253     89/<- %ecx 0/r32/eax
22254     # if (inout->is-deref?) inout-type = inout-type->payload
22255     8b/-> *(esi+0x10) 0/r32/eax  # Stmt-var-is-deref
22256     3d/compare-eax-and 0/imm32/false
22257     {
22258       74/jump-if-= break/disp8
22259       (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
22260       # if inout-type->right is null, t = inout-type->left
22261       81 7/subop/compare *(eax+0xc) 0/imm32  # Type-tree-right
22262       {
22263         75/jump-if-!= break/disp8
22264         (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
22265       }
22266       89/<- %ecx 0/r32/eax
22267     }
22268     # if output not in register, abort
22269     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
22270     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
22271     3d/compare-eax-and 0/imm32
22272     0f 84/jump-if-= $check-mu-copy-stmt:error-output-not-in-register/disp32
22273     # var output-type/eax: (addr type-tree) = output->value->type
22274     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
22275     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
22276     # if (inout-type == output-type) return
22277     (type-match? %eax %ecx %edx)  # => eax
22278     3d/compare-eax-and 0/imm32
22279     0f 85/jump-if-!= $check-mu-copy-stmt:end/disp32
22280     # if output is an addr and inout is 0, return
22281     {
22282       (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
22283       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
22284       (mu-addr-type? %eax)  # => eax
22285       3d/compare-eax-and 0/imm32/false
22286       74/jump-if-= break/disp8
22287       (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
22288       (lookup *eax *(eax+4))  # Var-name Var-name => eax
22289       (string-equal? %eax "0")  # => eax
22290       3d/compare-eax-and 0/imm32/false
22291       74/jump-if-= break/disp8
22292       e9/jump $check-mu-copy-stmt:end/disp32
22293     }
22294     # if output is an offset and inout is 0, return
22295     {
22296       (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
22297       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
22298       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
22299       75/jump-if-!= break/disp8
22300       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
22301       (simple-mu-type? %eax 7)  # offset => eax
22302       3d/compare-eax-and 0/imm32/false
22303       74/jump-if-= break/disp8
22304       (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
22305       (lookup *eax *(eax+4))  # Var-name Var-name => eax
22306       (string-equal? %eax "0")  # => eax
22307       3d/compare-eax-and 0/imm32/false
22308       74/jump-if-= break/disp8
22309       e9/jump $check-mu-copy-stmt:end/disp32
22310     }
22311     # if output is a byte, abort if inout is not a literal. Otherwise return.
22312     {
22313       (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
22314       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
22315       (simple-mu-type? %eax 8)  # byte => eax
22316       3d/compare-eax-and 0/imm32/false
22317       74/jump-if-= break/disp8
22318       (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
22319       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
22320       (simple-mu-type? %eax 0)  # literal => eax
22321       3d/compare-eax-and 0/imm32/false
22322       0f 84/jump-if-= $check-mu-copy-stmt:error-non-literal-to-byte/disp32
22323       eb/jump $check-mu-copy-stmt:end/disp8
22324     }
22325     # if output is not number-like, abort
22326     (check-mu-numberlike-output %edi *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
22327 $check-mu-copy-stmt:end:
22328     # . reclaim locals
22329     81 0/subop/add %esp 0x6c/imm32
22330     # . restore registers
22331     5f/pop-to-edi
22332     5e/pop-to-esi
22333     5a/pop-to-edx
22334     59/pop-to-ecx
22335     58/pop-to-eax
22336     # . epilogue
22337     89/<- %esp 5/r32/ebp
22338     5d/pop-to-ebp
22339     c3/return
22341 $check-mu-copy-stmt:error-no-inout:
22342     (write-buffered *(ebp+0x10) "fn ")
22343     8b/-> *(ebp+0xc) 0/r32/eax
22344     (lookup *eax *(eax+4))  # Function-name Function-name => eax
22345     (write-buffered *(ebp+0x10) %eax)
22346     (write-buffered *(ebp+0x10) ": stmt 'copy' expects an inout\n")
22347     (flush *(ebp+0x10))
22348     (stop *(ebp+0x14) 1)
22349     # never gets here
22351 $check-mu-copy-stmt:error-too-many-inouts:
22352     (write-buffered *(ebp+0x10) "fn ")
22353     8b/-> *(ebp+0xc) 0/r32/eax
22354     (lookup *eax *(eax+4))  # Function-name Function-name => eax
22355     (write-buffered *(ebp+0x10) %eax)
22356     (write-buffered *(ebp+0x10) ": stmt 'copy' must have just one inout\n")
22357     (flush *(ebp+0x10))
22358     (stop *(ebp+0x14) 1)
22359     # never gets here
22361 $check-mu-copy-stmt:error-no-output:
22362     (write-buffered *(ebp+0x10) "fn ")
22363     8b/-> *(ebp+0xc) 0/r32/eax
22364     (lookup *eax *(eax+4))  # Function-name Function-name => eax
22365     (write-buffered *(ebp+0x10) %eax)
22366     (write-buffered *(ebp+0x10) ": stmt 'copy' expects an output\n")
22367     (flush *(ebp+0x10))
22368     (stop *(ebp+0x14) 1)
22369     # never gets here
22371 $check-mu-copy-stmt:error-output-not-in-register:
22372     (write-buffered *(ebp+0x10) "fn ")
22373     8b/-> *(ebp+0xc) 0/r32/eax
22374     (lookup *eax *(eax+4))  # Function-name Function-name => eax
22375     (write-buffered *(ebp+0x10) %eax)
22376     (write-buffered *(ebp+0x10) ": stmt copy: output '")
22377     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
22378     (lookup *eax *(eax+4))  # Var-name Var-name => eax
22379     (write-buffered *(ebp+0x10) %eax)
22380     (write-buffered *(ebp+0x10) "' not in a register\n")
22381     (flush *(ebp+0x10))
22382     (stop *(ebp+0x14) 1)
22383     # never gets here
22385 $check-mu-copy-stmt:error-too-many-outputs:
22386     (write-buffered *(ebp+0x10) "fn ")
22387     8b/-> *(ebp+0xc) 0/r32/eax
22388     (lookup *eax *(eax+4))  # Function-name Function-name => eax
22389     (write-buffered *(ebp+0x10) %eax)
22390     (write-buffered *(ebp+0x10) ": stmt 'copy' must have just one output\n")
22391     (flush *(ebp+0x10))
22392     (stop *(ebp+0x14) 1)
22393     # never gets here
22395 $check-mu-copy-stmt:error-inout-too-large:
22396     (write-buffered *(ebp+0x10) "fn ")
22397     8b/-> *(ebp+0xc) 0/r32/eax
22398     (lookup *eax *(eax+4))  # Function-name Function-name => eax
22399     (write-buffered *(ebp+0x10) %eax)
22400     (write-buffered *(ebp+0x10) ": stmt copy: '")
22401     (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
22402     (lookup *eax *(eax+4))  # Var-name Var-name => eax
22403     (write-buffered *(ebp+0x10) %eax)
22404     (write-buffered *(ebp+0x10) "' is too large to fit in a register\n")
22405     (flush *(ebp+0x10))
22406     (stop *(ebp+0x14) 1)
22407     # never gets here
22409 $check-mu-copy-stmt:error-non-literal-to-byte:
22410     (write-buffered *(ebp+0x10) "fn ")
22411     8b/-> *(ebp+0xc) 0/r32/eax
22412     (lookup *eax *(eax+4))  # Function-name Function-name => eax
22413     (write-buffered *(ebp+0x10) %eax)
22414     (write-buffered *(ebp+0x10) ": stmt copy: cannot copy non-literal to '")
22415     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
22416     (lookup *eax *(eax+4))  # Var-name Var-name => eax
22417     (write-buffered *(ebp+0x10) %eax)
22418     (write-buffered *(ebp+0x10) "' of type byte; use copy-byte\n")
22419     (flush *(ebp+0x10))
22420     (stop *(ebp+0x14) 1)
22421     # never gets here
22423 check-mu-copy-to-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
22424     # . prologue
22425     55/push-ebp
22426     89/<- %ebp 4/r32/esp
22427     # . save registers
22428     50/push-eax
22429     51/push-ecx
22430     52/push-edx
22431     53/push-ebx
22432     56/push-esi
22433     57/push-edi
22434     # var type-parameters/edx: (addr table (handle array byte) (addr type-tree) 8)
22435     81 5/subop/subtract %esp 0x60/imm32
22436     68/push 0x60/imm32/size
22437     68/push 0/imm32/read
22438     68/push 0/imm32/write
22439     89/<- %edx 4/r32/esp
22440     # esi = stmt
22441     8b/-> *(ebp+8) 6/r32/esi
22442 $check-mu-copy-to-stmt:check-for-output:
22443     # if stmt->outputs abort
22444     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
22445     3d/compare-eax-and 0/imm32
22446     0f 85/jump-if-!= $check-mu-copy-to-stmt:error-too-many-outputs/disp32
22447 $check-mu-copy-to-stmt:get-dest:
22448     # var dest/edi: (addr stmt-var) = stmt->inouts
22449     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
22450     89/<- %edi 0/r32/eax
22451     # zero inouts
22452     3d/compare-eax-and 0/imm32
22453     0f 84/jump-if-= $check-mu-copy-to-stmt:error-incorrect-inouts/disp32
22454 $check-mu-copy-to-stmt:get-src:
22455     # var src/esi: (addr stmt-var) = dest->next
22456     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
22457     89/<- %esi 0/r32/eax
22458     # 1 inout
22459     3d/compare-eax-and 0/imm32
22460     0f 84/jump-if-= $check-mu-copy-to-stmt:error-incorrect-inouts/disp32
22461     # > 2 inouts
22462     (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
22463     3d/compare-eax-and 0/imm32
22464     0f 85/jump-if-!= $check-mu-copy-to-stmt:error-incorrect-inouts/disp32
22465 $check-mu-copy-to-stmt:types:
22466     # if src is not a scalar, abort
22467     (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
22468     (size-of %eax)  # => eax
22469     3d/compare-eax-and 4/imm32
22470     0f 8f/jump-if-> $check-mu-copy-to-stmt:error-src-too-large/disp32
22471     # var src-type/ecx: (addr type-tree) = src->value->type
22472     (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
22473     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
22474     89/<- %ecx 0/r32/eax
22475     # if src not in register or literal, abort
22476     # (we can't use stack-offset because it hasn't been computed yet)
22477     {
22478       (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
22479       (lookup *(eax+0x8) *(eax+0xc))  # Var-type Var-type => eax
22480       (simple-mu-type? %eax 0)  # => eax
22481       3d/compare-eax-and 0/imm32
22482       75/jump-if-!= break/disp8
22483       (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
22484       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
22485       3d/compare-eax-and 0/imm32
22486       75/jump-if-!= break/disp8
22487       e9/jump $check-mu-copy-to-stmt:error-src-not-literal-or-in-register/disp32
22488     }
22489     # var dest-type/ebx: (addr type-tree) = dest->value->type
22490     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
22491     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
22492     89/<- %ebx 0/r32/eax
22493     # if (dest->is-deref?) dest-type = dest-type->payload
22494 $check-mu-copy-to-stmt:check-dest-deref:
22495     8b/-> *(edi+0x10) 0/r32/eax  # Stmt-var-is-deref
22496     3d/compare-eax-and 0/imm32/false
22497     {
22498       74/jump-if-= break/disp8
22499       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
22500 $check-mu-copy-to-stmt:dest-is-deref:
22501       # if dest-type->right is null, dest-type = dest-type->left
22502       81 7/subop/compare *(eax+0xc) 0/imm32  # Type-tree-right
22503       {
22504         75/jump-if-!= break/disp8
22505 $check-mu-copy-to-stmt:dest-is-deref2:
22506         (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
22507       }
22508       89/<- %ebx 0/r32/eax
22509     }
22510     # if dest is a byte and src is not a literal, abort
22511     {
22512 $check-mu-copy-to-stmt:final-check-byte:
22513       (simple-mu-type? %ebx 8)  # byte => eax
22514       3d/compare-eax-and 0/imm32/false
22515       74/jump-if-= break/disp8
22516       (simple-mu-type? %ecx 0)  # literal => eax
22517       3d/compare-eax-and 0/imm32/false
22518       0f 84/jump-if-= $check-mu-copy-to-stmt:error-non-literal-to-byte/disp32
22519     }
22520     # if (src-type == dest-type) return
22521     (type-match? %ebx %ecx %edx)  # => eax
22522     3d/compare-eax-and 0/imm32
22523     0f 85/jump-if-!= $check-mu-copy-to-stmt:end/disp32
22524     # if dest is an addr and src is 0, return
22525     {
22526 $check-mu-copy-to-stmt:final-check-addr:
22527       (mu-addr-type? %ebx)  # => eax
22528       3d/compare-eax-and 0/imm32/false
22529       74/jump-if-= break/disp8
22530       (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
22531       (lookup *eax *(eax+4))  # Var-name Var-name => eax
22532       (string-equal? %eax "0")  # => eax
22533       3d/compare-eax-and 0/imm32/false
22534       74/jump-if-= break/disp8
22535       e9/jump $check-mu-copy-to-stmt:end/disp32
22536     }
22537     # if dest is an offset and src is 0, return
22538     {
22539 $check-mu-copy-to-stmt:final-check-offset:
22540       81 7/subop/compare *ebx 0/imm32/false  # Type-tree-is-atom
22541       75/jump-if-!= break/disp8
22542       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
22543       (simple-mu-type? %eax 7)  # offset => eax
22544       3d/compare-eax-and 0/imm32/false
22545       74/jump-if-= break/disp8
22546       (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
22547       (lookup *eax *(eax+4))  # Var-name Var-name => eax
22548       (string-equal? %eax "0")  # => eax
22549       3d/compare-eax-and 0/imm32/false
22550       74/jump-if-= break/disp8
22551       e9/jump $check-mu-copy-to-stmt:end/disp32
22552     }
22553     # if dest is not number-like, abort
22554     (check-mu-numberlike-arg %edi *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
22555 $check-mu-copy-to-stmt:end:
22556     # . reclaim locals
22557     81 0/subop/add %esp 0x6c/imm32
22558     # . restore registers
22559     5f/pop-to-edi
22560     5e/pop-to-esi
22561     5b/pop-to-ebx
22562     5a/pop-to-edx
22563     59/pop-to-ecx
22564     58/pop-to-eax
22565     # . epilogue
22566     89/<- %esp 5/r32/ebp
22567     5d/pop-to-ebp
22568     c3/return
22570 $check-mu-copy-to-stmt:error-incorrect-inouts:
22571     (write-buffered *(ebp+0x10) "fn ")
22572     8b/-> *(ebp+0xc) 0/r32/eax
22573     (lookup *eax *(eax+4))  # Function-name Function-name => eax
22574     (write-buffered *(ebp+0x10) %eax)
22575     (write-buffered *(ebp+0x10) ": stmt 'copy-to' must have two inouts\n")
22576     (flush *(ebp+0x10))
22577     (stop *(ebp+0x14) 1)
22578     # never gets here
22580 $check-mu-copy-to-stmt:error-too-many-outputs:
22581     (write-buffered *(ebp+0x10) "fn ")
22582     8b/-> *(ebp+0xc) 0/r32/eax
22583     (lookup *eax *(eax+4))  # Function-name Function-name => eax
22584     (write-buffered *(ebp+0x10) %eax)
22585     (write-buffered *(ebp+0x10) ": stmt 'copy-to' must not have any outputs\n")
22586     (flush *(ebp+0x10))
22587     (stop *(ebp+0x14) 1)
22588     # never gets here
22590 $check-mu-copy-to-stmt:error-src-not-literal-or-in-register:
22591     (write-buffered *(ebp+0x10) "fn ")
22592     8b/-> *(ebp+0xc) 0/r32/eax
22593     (lookup *eax *(eax+4))  # Function-name Function-name => eax
22594     (write-buffered *(ebp+0x10) %eax)
22595     (write-buffered *(ebp+0x10) ": stmt copy-to: source (second inout) is in memory\n")
22596     (flush *(ebp+0x10))
22597     (stop *(ebp+0x14) 1)
22598     # never gets here
22600 $check-mu-copy-to-stmt:error-src-too-large:
22601     (write-buffered *(ebp+0x10) "fn ")
22602     8b/-> *(ebp+0xc) 0/r32/eax
22603     (lookup *eax *(eax+4))  # Function-name Function-name => eax
22604     (write-buffered *(ebp+0x10) %eax)
22605     (write-buffered *(ebp+0x10) ": stmt copy-to: '")
22606     (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
22607     (lookup *eax *(eax+4))  # Var-name Var-name => eax
22608     (write-buffered *(ebp+0x10) %eax)
22609     (write-buffered *(ebp+0x10) "' is too large to copy\n")
22610     (flush *(ebp+0x10))
22611     (stop *(ebp+0x14) 1)
22612     # never gets here
22614 $check-mu-copy-to-stmt:error-non-literal-to-byte:
22615     (write-buffered *(ebp+0x10) "fn ")
22616     8b/-> *(ebp+0xc) 0/r32/eax
22617     (lookup *eax *(eax+4))  # Function-name Function-name => eax
22618     (write-buffered *(ebp+0x10) %eax)
22619     (write-buffered *(ebp+0x10) ": stmt copy-to: cannot copy non-literal to type byte; use copy-byte-to\n")
22620     (flush *(ebp+0x10))
22621     (stop *(ebp+0x14) 1)
22622     # never gets here
22624 check-mu-copy-byte-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
22625     # . prologue
22626     55/push-ebp
22627     89/<- %ebp 4/r32/esp
22628     # . save registers
22629     50/push-eax
22630     51/push-ecx
22631     52/push-edx
22632     56/push-esi
22633     57/push-edi
22634     # var type-parameters/edx: (addr table (handle array byte) (addr type-tree) 8)
22635     81 5/subop/subtract %esp 0x60/imm32
22636     68/push 0x60/imm32/size
22637     68/push 0/imm32/read
22638     68/push 0/imm32/write
22639     89/<- %edx 4/r32/esp
22640 $check-mu-copy-byte-stmt:get-output:
22641     # esi = stmt
22642     8b/-> *(ebp+8) 6/r32/esi
22643     # var output/edi: (addr stmt-var) = stmt->outputs
22644     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
22645     89/<- %edi 0/r32/eax
22646     # zero outputs
22647     3d/compare-eax-and 0/imm32
22648     0f 84/jump-if-= $check-mu-copy-byte-stmt:error-no-output/disp32
22649     # > 1 output
22650     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
22651     3d/compare-eax-and 0/imm32
22652     0f 85/jump-if-!= $check-mu-copy-byte-stmt:error-too-many-outputs/disp32
22653 $check-mu-copy-byte-stmt:get-inout:
22654     # var inout/esi: (addr stmt-var) = stmt->inouts
22655     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
22656     89/<- %esi 0/r32/eax
22657     # zero inouts
22658     3d/compare-eax-and 0/imm32
22659     0f 84/jump-if-= $check-mu-copy-byte-stmt:error-no-inout/disp32
22660     # > 1 inout
22661     (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
22662     3d/compare-eax-and 0/imm32
22663     0f 85/jump-if-!= $check-mu-copy-byte-stmt:error-too-many-inouts/disp32
22664 $check-mu-copy-byte-stmt:types:
22665     # if inout is not a scalar, abort
22666     (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
22667     (size-of %eax)  # => eax
22668     3d/compare-eax-and 4/imm32
22669     0f 8f/jump-if-> $check-mu-copy-byte-stmt:error-inout-too-large/disp32
22670     # var inout-type/ecx: (addr type-tree) = inout->value->type
22671     (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
22672     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
22673     89/<- %ecx 0/r32/eax
22674 $check-mu-copy-byte-stmt:check-inout-deref:
22675     # if (inout->is-deref?) inout-type = inout-type->payload
22676     8b/-> *(esi+0x10) 0/r32/eax  # Stmt-var-is-deref
22677     3d/compare-eax-and 0/imm32/false
22678     {
22679       74/jump-if-= break/disp8
22680 $check-mu-copy-byte-stmt:inout-is-deref:
22681       (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
22682       # if inout-type->right is null, t = inout-type->left
22683       81 7/subop/compare *(eax+0xc) 0/imm32  # Type-tree-right
22684       {
22685         75/jump-if-!= break/disp8
22686 $check-mu-copy-byte-stmt:inout-is-deref2:
22687         (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
22688       }
22689       89/<- %ecx 0/r32/eax
22690     }
22691     # if output not in register, abort
22692     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
22693     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
22694     3d/compare-eax-and 0/imm32
22695     0f 84/jump-if-= $check-mu-copy-byte-stmt:error-output-not-in-register/disp32
22696     # var output-type/eax: (addr type-tree) = output->value->type
22697     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
22698     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
22699     # if output is not of type byte, abort
22700     (simple-mu-type? %eax 8)  # byte => eax
22701     3d/compare-eax-and 0/imm32
22702     0f 84/jump-if-= $check-mu-copy-byte-stmt:error-invalid-output-type/disp32
22703 $check-mu-copy-byte-stmt:end:
22704     # . reclaim locals
22705     81 0/subop/add %esp 0x6c/imm32
22706     # . restore registers
22707     5f/pop-to-edi
22708     5e/pop-to-esi
22709     5a/pop-to-edx
22710     59/pop-to-ecx
22711     58/pop-to-eax
22712     # . epilogue
22713     89/<- %esp 5/r32/ebp
22714     5d/pop-to-ebp
22715     c3/return
22717 $check-mu-copy-byte-stmt:error-no-inout:
22718     (write-buffered *(ebp+0x10) "fn ")
22719     8b/-> *(ebp+0xc) 0/r32/eax
22720     (lookup *eax *(eax+4))  # Function-name Function-name => eax
22721     (write-buffered *(ebp+0x10) %eax)
22722     (write-buffered *(ebp+0x10) ": stmt 'copy-byte' expects an inout\n")
22723     (flush *(ebp+0x10))
22724     (stop *(ebp+0x14) 1)
22725     # never gets here
22727 $check-mu-copy-byte-stmt:error-too-many-inouts:
22728     (write-buffered *(ebp+0x10) "fn ")
22729     8b/-> *(ebp+0xc) 0/r32/eax
22730     (lookup *eax *(eax+4))  # Function-name Function-name => eax
22731     (write-buffered *(ebp+0x10) %eax)
22732     (write-buffered *(ebp+0x10) ": stmt 'copy-byte' must have just one inout\n")
22733     (flush *(ebp+0x10))
22734     (stop *(ebp+0x14) 1)
22735     # never gets here
22737 $check-mu-copy-byte-stmt:error-no-output:
22738     (write-buffered *(ebp+0x10) "fn ")
22739     8b/-> *(ebp+0xc) 0/r32/eax
22740     (lookup *eax *(eax+4))  # Function-name Function-name => eax
22741     (write-buffered *(ebp+0x10) %eax)
22742     (write-buffered *(ebp+0x10) ": stmt 'copy-byte' expects an output\n")
22743     (flush *(ebp+0x10))
22744     (stop *(ebp+0x14) 1)
22745     # never gets here
22747 $check-mu-copy-byte-stmt:error-output-not-in-register:
22748     (write-buffered *(ebp+0x10) "fn ")
22749     8b/-> *(ebp+0xc) 0/r32/eax
22750     (lookup *eax *(eax+4))  # Function-name Function-name => eax
22751     (write-buffered *(ebp+0x10) %eax)
22752     (write-buffered *(ebp+0x10) ": stmt copy-byte: output '")
22753     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
22754     (lookup *eax *(eax+4))  # Var-name Var-name => eax
22755     (write-buffered *(ebp+0x10) %eax)
22756     (write-buffered *(ebp+0x10) "' not in a register\n")
22757     (flush *(ebp+0x10))
22758     (stop *(ebp+0x14) 1)
22759     # never gets here
22761 $check-mu-copy-byte-stmt:error-too-many-outputs:
22762     (write-buffered *(ebp+0x10) "fn ")
22763     8b/-> *(ebp+0xc) 0/r32/eax
22764     (lookup *eax *(eax+4))  # Function-name Function-name => eax
22765     (write-buffered *(ebp+0x10) %eax)
22766     (write-buffered *(ebp+0x10) ": stmt 'copy-byte' must have just one output\n")
22767     (flush *(ebp+0x10))
22768     (stop *(ebp+0x14) 1)
22769     # never gets here
22771 $check-mu-copy-byte-stmt:error-invalid-output-type:
22772     (write-buffered *(ebp+0x10) "fn ")
22773     8b/-> *(ebp+0xc) 0/r32/eax
22774     (lookup *eax *(eax+4))  # Function-name Function-name => eax
22775     (write-buffered *(ebp+0x10) %eax)
22776     (write-buffered *(ebp+0x10) ": stmt 'copy-byte' must write to output of type byte\n")
22777     (flush *(ebp+0x10))
22778     (stop *(ebp+0x14) 1)
22779     # never gets here
22781 $check-mu-copy-byte-stmt:error-inout-too-large:
22782     (write-buffered *(ebp+0x10) "fn ")
22783     8b/-> *(ebp+0xc) 0/r32/eax
22784     (lookup *eax *(eax+4))  # Function-name Function-name => eax
22785     (write-buffered *(ebp+0x10) %eax)
22786     (write-buffered *(ebp+0x10) ": stmt copy-byte: '")
22787     (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
22788     (lookup *eax *(eax+4))  # Var-name Var-name => eax
22789     (write-buffered *(ebp+0x10) %eax)
22790     (write-buffered *(ebp+0x10) "' is too large to fit in a register\n")
22791     (flush *(ebp+0x10))
22792     (stop *(ebp+0x14) 1)
22793     # never gets here
22795 check-mu-copy-byte-to-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
22796     # . prologue
22797     55/push-ebp
22798     89/<- %ebp 4/r32/esp
22799     # . save registers
22800     50/push-eax
22801     52/push-edx
22802     53/push-ebx
22803     56/push-esi
22804     57/push-edi
22805     # var type-parameters/edx: (addr table (handle array byte) (addr type-tree) 8)
22806     81 5/subop/subtract %esp 0x60/imm32
22807     68/push 0x60/imm32/size
22808     68/push 0/imm32/read
22809     68/push 0/imm32/write
22810     89/<- %edx 4/r32/esp
22811     # esi = stmt
22812     8b/-> *(ebp+8) 6/r32/esi
22813 $check-mu-copy-byte-to-stmt:check-for-output:
22814     # if stmt->outputs abort
22815     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
22816     3d/compare-eax-and 0/imm32
22817     0f 85/jump-if-!= $check-mu-copy-byte-to-stmt:error-too-many-outputs/disp32
22818 $check-mu-copy-byte-to-stmt:get-dest:
22819     # var dest/edi: (addr stmt-var) = stmt->inouts
22820     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
22821     89/<- %edi 0/r32/eax
22822     # zero inouts
22823     3d/compare-eax-and 0/imm32
22824     0f 84/jump-if-= $check-mu-copy-byte-to-stmt:error-incorrect-inouts/disp32
22825 $check-mu-copy-byte-to-stmt:get-src:
22826     # var src/esi: (addr stmt-var) = dest->next
22827     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
22828     89/<- %esi 0/r32/eax
22829     # 1 inout
22830     3d/compare-eax-and 0/imm32
22831     0f 84/jump-if-= $check-mu-copy-byte-to-stmt:error-incorrect-inouts/disp32
22832     # > 2 inouts
22833     (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
22834     3d/compare-eax-and 0/imm32
22835     0f 85/jump-if-!= $check-mu-copy-byte-to-stmt:error-incorrect-inouts/disp32
22836 $check-mu-copy-byte-to-stmt:types:
22837     # if src is not a scalar, abort
22838     (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
22839     (size-of %eax)  # => eax
22840     3d/compare-eax-and 4/imm32
22841     0f 8f/jump-if-> $check-mu-copy-byte-to-stmt:error-src-too-large/disp32
22842     # if src not in register, abort
22843     {
22844       (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
22845       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
22846       3d/compare-eax-and 0/imm32
22847       75/jump-if-!= break/disp8
22848       e9/jump $check-mu-copy-byte-to-stmt:error-src-not-in-register/disp32
22849     }
22850     # var dest-type/ebx: (addr type-tree) = dest->value->type
22851     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
22852     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
22853     89/<- %ebx 0/r32/eax
22854     # if (dest->is-deref?) dest-type = dest-type->payload
22855 $check-mu-copy-byte-to-stmt:check-dest-deref:
22856     8b/-> *(edi+0x10) 0/r32/eax  # Stmt-var-is-deref
22857     3d/compare-eax-and 0/imm32/false
22858     {
22859       74/jump-if-= break/disp8
22860       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
22861 $check-mu-copy-byte-to-stmt:dest-is-deref:
22862       # if dest-type->right is null, dest-type = dest-type->left
22863       81 7/subop/compare *(eax+0xc) 0/imm32  # Type-tree-right
22864       {
22865         75/jump-if-!= break/disp8
22866 $check-mu-copy-byte-to-stmt:dest-is-deref2:
22867         (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
22868       }
22869       89/<- %ebx 0/r32/eax
22870     }
22871     # if dest is not a byte, abort
22872     (simple-mu-type? %ebx 8)  # byte => eax
22873     3d/compare-eax-and 0/imm32/false
22874     0f 84/jump-if-= $check-mu-copy-byte-to-stmt:error-invalid-dest-type/disp32
22875 $check-mu-copy-byte-to-stmt:end:
22876     # . reclaim locals
22877     81 0/subop/add %esp 0x6c/imm32
22878     # . restore registers
22879     5f/pop-to-edi
22880     5e/pop-to-esi
22881     5b/pop-to-ebx
22882     5a/pop-to-edx
22883     58/pop-to-eax
22884     # . epilogue
22885     89/<- %esp 5/r32/ebp
22886     5d/pop-to-ebp
22887     c3/return
22889 $check-mu-copy-byte-to-stmt:error-incorrect-inouts:
22890     (write-buffered *(ebp+0x10) "fn ")
22891     8b/-> *(ebp+0xc) 0/r32/eax
22892     (lookup *eax *(eax+4))  # Function-name Function-name => eax
22893     (write-buffered *(ebp+0x10) %eax)
22894     (write-buffered *(ebp+0x10) ": stmt 'copy-byte-to' must have two inouts\n")
22895     (flush *(ebp+0x10))
22896     (stop *(ebp+0x14) 1)
22897     # never gets here
22899 $check-mu-copy-byte-to-stmt:error-too-many-outputs:
22900     (write-buffered *(ebp+0x10) "fn ")
22901     8b/-> *(ebp+0xc) 0/r32/eax
22902     (lookup *eax *(eax+4))  # Function-name Function-name => eax
22903     (write-buffered *(ebp+0x10) %eax)
22904     (write-buffered *(ebp+0x10) ": stmt 'copy-byte-to' must not have any outputs\n")
22905     (flush *(ebp+0x10))
22906     (stop *(ebp+0x14) 1)
22907     # never gets here
22909 $check-mu-copy-byte-to-stmt:error-src-not-in-register:
22910     (write-buffered *(ebp+0x10) "fn ")
22911     8b/-> *(ebp+0xc) 0/r32/eax
22912     (lookup *eax *(eax+4))  # Function-name Function-name => eax
22913     (write-buffered *(ebp+0x10) %eax)
22914     (write-buffered *(ebp+0x10) ": stmt copy-byte-to: source (second inout) must be in a register\n")
22915     (flush *(ebp+0x10))
22916     (stop *(ebp+0x14) 1)
22917     # never gets here
22919 $check-mu-copy-byte-to-stmt:error-invalid-dest-type:
22920     (write-buffered *(ebp+0x10) "fn ")
22921     8b/-> *(ebp+0xc) 0/r32/eax
22922     (lookup *eax *(eax+4))  # Function-name Function-name => eax
22923     (write-buffered *(ebp+0x10) %eax)
22924     (write-buffered *(ebp+0x10) ": stmt copy-byte-to: '")
22925     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
22926     (lookup *eax *(eax+4))  # Var-name Var-name => eax
22927     (write-buffered *(ebp+0x10) %eax)
22928     (write-buffered *(ebp+0x10) "' must be a byte\n")
22929     (flush *(ebp+0x10))
22930     (stop *(ebp+0x14) 1)
22931     # never gets here
22933 $check-mu-copy-byte-to-stmt:error-src-too-large:
22934     (write-buffered *(ebp+0x10) "fn ")
22935     8b/-> *(ebp+0xc) 0/r32/eax
22936     (lookup *eax *(eax+4))  # Function-name Function-name => eax
22937     (write-buffered *(ebp+0x10) %eax)
22938     (write-buffered *(ebp+0x10) ": stmt copy-byte-to: '")
22939     (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
22940     (lookup *eax *(eax+4))  # Var-name Var-name => eax
22941     (write-buffered *(ebp+0x10) %eax)
22942     (write-buffered *(ebp+0x10) "' is too large to copy\n")
22943     (flush *(ebp+0x10))
22944     (stop *(ebp+0x14) 1)
22945     # never gets here
22947 check-mu-compare-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
22948     # . prologue
22949     55/push-ebp
22950     89/<- %ebp 4/r32/esp
22951     # . save registers
22952     50/push-eax
22953     51/push-ecx
22954     52/push-edx
22955     53/push-ebx
22956     56/push-esi
22957     57/push-edi
22958     # var type-parameters/edx: (addr table (handle array byte) (addr type-tree) 8)
22959     81 5/subop/subtract %esp 0x60/imm32
22960     68/push 0x60/imm32/size
22961     68/push 0/imm32/read
22962     68/push 0/imm32/write
22963     89/<- %edx 4/r32/esp
22964     # esi = stmt
22965     8b/-> *(ebp+8) 6/r32/esi
22966 $check-mu-compare-stmt:check-for-output:
22967     # if stmt->outputs abort
22968     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
22969     3d/compare-eax-and 0/imm32
22970     0f 85/jump-if-!= $check-mu-compare-stmt:error-too-many-outputs/disp32
22971 $check-mu-compare-stmt:get-left:
22972     # var left/edi: (addr stmt-var) = stmt->inouts
22973     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
22974     89/<- %edi 0/r32/eax
22975     # zero inouts
22976     3d/compare-eax-and 0/imm32
22977     0f 84/jump-if-= $check-mu-compare-stmt:error-incorrect-inouts/disp32
22978 $check-mu-compare-stmt:get-right:
22979     # var right/esi: (addr stmt-var) = left->next
22980     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
22981     89/<- %esi 0/r32/eax
22982     # 1 inout
22983     3d/compare-eax-and 0/imm32
22984     0f 84/jump-if-= $check-mu-compare-stmt:error-incorrect-inouts/disp32
22985     # > 2 inouts
22986     (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
22987     3d/compare-eax-and 0/imm32
22988     0f 85/jump-if-!= $check-mu-compare-stmt:error-incorrect-inouts/disp32
22989     # if both inouts are in memory, abort
22990     {
22991 $check-mu-compare-stmt:both-in-mem:
22992       (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
22993       (lookup *(eax+0x8) *(eax+0xc))  # Var-type Var-type => eax
22994       (simple-mu-type? %eax 0)  # => eax
22995       3d/compare-eax-and 0/imm32
22996       0f 85/jump-if-!= break/disp32
22997       (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
22998       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
22999       3d/compare-eax-and 0/imm32
23000       75/jump-if-!= break/disp8
23001       (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
23002       (lookup *(eax+0x8) *(eax+0xc))  # Var-type Var-type => eax
23003       (simple-mu-type? %eax 0)  # => eax
23004       3d/compare-eax-and 0/imm32
23005       75/jump-if-!= break/disp8
23006       (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
23007       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
23008       3d/compare-eax-and 0/imm32
23009       75/jump-if-!= break/disp8
23010       e9/jump $check-mu-compare-stmt:error-both-in-memory/disp32
23011     }
23012 $check-mu-compare-stmt:types:
23013     # var right-type/ecx: (addr type-tree) = right->value->type
23014     (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
23015     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
23016     89/<- %ecx 0/r32/eax
23017     # if (right->is-deref?) right-type = right-type->payload
23018     8b/-> *(esi+0x10) 0/r32/eax  # Stmt-var-is-deref
23019     3d/compare-eax-and 0/imm32/false
23020     {
23021       74/jump-if-= break/disp8
23022       (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
23023       # if right-type->right is null, right-type = right-type->left
23024       81 7/subop/compare *(eax+0xc) 0/imm32  # Type-tree-right
23025       {
23026         75/jump-if-!= break/disp8
23027         (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
23028       }
23029       89/<- %ecx 0/r32/eax
23030     }
23031     # if right-type is a literal string, abort
23032     (simple-mu-type? %ecx 0x10)  # string-literal => eax
23033     3d/compare-eax-and 0/imm32/false
23034     0f 85/jump-if-!= $check-mu-compare-stmt:error-right-string-literal/disp32
23035     # if right is not a scalar, abort
23036     (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
23037     (size-of %eax)  # => eax
23038     3d/compare-eax-and 4/imm32
23039     0f 8f/jump-if-> $check-mu-compare-stmt:error-right-too-large/disp32
23040     # if left is not a scalar, abort
23041     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
23042     (size-of %eax)  # => eax
23043     3d/compare-eax-and 4/imm32
23044     0f 8f/jump-if-> $check-mu-compare-stmt:error-left-too-large/disp32
23045     # var left-type/ebx: (addr type-tree) = left->value->type
23046     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
23047     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
23048     89/<- %ebx 0/r32/eax
23049     # if (left->is-deref?) left-type = left-type->payload
23050     8b/-> *(edi+0x10) 0/r32/eax  # Stmt-var-is-deref
23051     3d/compare-eax-and 0/imm32/false
23052     {
23053       74/jump-if-= break/disp8
23054       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
23055       # if left-type->right is null, left-type = left-type->left
23056       81 7/subop/compare *(eax+0xc) 0/imm32  # Type-tree-right
23057       {
23058         75/jump-if-!= break/disp8
23059         (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
23060       }
23061       89/<- %ebx 0/r32/eax
23062     }
23063     # if (left-type == right-type) return
23064     (type-match? %ebx %ecx %edx)  # => eax
23065     3d/compare-eax-and 0/imm32
23066     0f 85/jump-if-!= $check-mu-compare-stmt:end/disp32
23067     # if left is an addr and right is 0, return
23068     {
23069       (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
23070       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
23071       (mu-addr-type? %eax)  # => eax
23072       3d/compare-eax-and 0/imm32/false
23073       74/jump-if-= break/disp8
23074       (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
23075       (lookup *eax *(eax+4))  # Var-name Var-name => eax
23076       (string-equal? %eax "0")  # => eax
23077       3d/compare-eax-and 0/imm32/false
23078       74/jump-if-= break/disp8
23079       eb/jump $check-mu-compare-stmt:end/disp8
23080     }
23081     # if left is not number-like, abort
23082     (check-mu-numberlike-arg %edi *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
23083 $check-mu-compare-stmt:end:
23084     # . reclaim locals
23085     81 0/subop/add %esp 0x6c/imm32
23086     # . restore registers
23087     5f/pop-to-edi
23088     5e/pop-to-esi
23089     5b/pop-to-ebx
23090     5a/pop-to-edx
23091     59/pop-to-ecx
23092     58/pop-to-eax
23093     # . epilogue
23094     89/<- %esp 5/r32/ebp
23095     5d/pop-to-ebp
23096     c3/return
23098 $check-mu-compare-stmt:error-incorrect-inouts:
23099     (write-buffered *(ebp+0x10) "fn ")
23100     8b/-> *(ebp+0xc) 0/r32/eax
23101     (lookup *eax *(eax+4))  # Function-name Function-name => eax
23102     (write-buffered *(ebp+0x10) %eax)
23103     (write-buffered *(ebp+0x10) ": stmt 'compare' must have two inouts\n")
23104     (flush *(ebp+0x10))
23105     (stop *(ebp+0x14) 1)
23106     # never gets here
23108 $check-mu-compare-stmt:error-too-many-outputs:
23109     (write-buffered *(ebp+0x10) "fn ")
23110     8b/-> *(ebp+0xc) 0/r32/eax
23111     (lookup *eax *(eax+4))  # Function-name Function-name => eax
23112     (write-buffered *(ebp+0x10) %eax)
23113     (write-buffered *(ebp+0x10) ": stmt 'compare' must not have any outputs\n")
23114     (flush *(ebp+0x10))
23115     (stop *(ebp+0x14) 1)
23116     # never gets here
23118 $check-mu-compare-stmt:error-both-in-memory:
23119     (write-buffered *(ebp+0x10) "fn ")
23120     8b/-> *(ebp+0xc) 0/r32/eax
23121     (lookup *eax *(eax+4))  # Function-name Function-name => eax
23122     (write-buffered *(ebp+0x10) %eax)
23123     (write-buffered *(ebp+0x10) ": stmt compare: both inouts are in memory\n")
23124     (flush *(ebp+0x10))
23125     (stop *(ebp+0x14) 1)
23126     # never gets here
23128 $check-mu-compare-stmt:error-left-too-large:
23129     (write-buffered *(ebp+0x10) "fn ")
23130     8b/-> *(ebp+0xc) 0/r32/eax
23131     (lookup *eax *(eax+4))  # Function-name Function-name => eax
23132     (write-buffered *(ebp+0x10) %eax)
23133     (write-buffered *(ebp+0x10) ": stmt compare: '")
23134     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
23135     (lookup *eax *(eax+4))  # Var-name Var-name => eax
23136     (write-buffered *(ebp+0x10) %eax)
23137     (write-buffered *(ebp+0x10) "' is too large to compare\n")
23138     (flush *(ebp+0x10))
23139     (stop *(ebp+0x14) 1)
23140     # never gets here
23142 $check-mu-compare-stmt:error-right-too-large:
23143     (write-buffered *(ebp+0x10) "fn ")
23144     8b/-> *(ebp+0xc) 0/r32/eax
23145     (lookup *eax *(eax+4))  # Function-name Function-name => eax
23146     (write-buffered *(ebp+0x10) %eax)
23147     (write-buffered *(ebp+0x10) ": stmt compare: '")
23148     (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
23149     (lookup *eax *(eax+4))  # Var-name Var-name => eax
23150     (write-buffered *(ebp+0x10) %eax)
23151     (write-buffered *(ebp+0x10) "' is too large to compare\n")
23152     (flush *(ebp+0x10))
23153     (stop *(ebp+0x14) 1)
23154     # never gets here
23156 $check-mu-compare-stmt:error-right-string-literal:
23157     (write-buffered *(ebp+0x10) "fn ")
23158     8b/-> *(ebp+0xc) 0/r32/eax
23159     (lookup *eax *(eax+4))  # Function-name Function-name => eax
23160     (write-buffered *(ebp+0x10) %eax)
23161     (write-buffered *(ebp+0x10) ": stmt compare: string literal ")
23162     (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
23163     (lookup *eax *(eax+4))  # Var-name Var-name => eax
23164     (write-buffered *(ebp+0x10) %eax)
23165     (write-buffered *(ebp+0x10) " is not supported; use the string-equal? function\n")
23166     (flush *(ebp+0x10))
23167     (stop *(ebp+0x14) 1)
23168     # never gets here
23170 check-mu-address-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
23171     # . prologue
23172     55/push-ebp
23173     89/<- %ebp 4/r32/esp
23174     # . save registers
23175     50/push-eax
23176     51/push-ecx
23177     52/push-edx
23178     56/push-esi
23179     57/push-edi
23180 $check-mu-address-stmt:get-output:
23181     # esi = stmt
23182     8b/-> *(ebp+8) 6/r32/esi
23183     # var output/edi: (addr stmt-var) = stmt->outputs
23184     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
23185     89/<- %edi 0/r32/eax
23186     # zero outputs
23187     3d/compare-eax-and 0/imm32
23188     0f 84/jump-if-= $check-mu-address-stmt:error-no-output/disp32
23189     # > 1 output
23190     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
23191     3d/compare-eax-and 0/imm32
23192     0f 85/jump-if-!= $check-mu-address-stmt:error-too-many-outputs/disp32
23193 $check-mu-address-stmt:get-inout:
23194     # var inout/esi: (addr stmt-var) = stmt->inouts
23195     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
23196     89/<- %esi 0/r32/eax
23197     # zero inouts
23198     3d/compare-eax-and 0/imm32
23199     0f 84/jump-if-= $check-mu-address-stmt:error-no-inout/disp32
23200     # > 1 inout
23201     (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
23202     3d/compare-eax-and 0/imm32
23203     0f 85/jump-if-!= $check-mu-address-stmt:error-too-many-inouts/disp32
23204 $check-mu-address-stmt:types:
23205     # if output not in register, abort
23206     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
23207     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
23208     3d/compare-eax-and 0/imm32
23209     0f 84/jump-if-= $check-mu-address-stmt:error-output-not-in-register/disp32
23210     # var output-type/edx: (addr type-tree) = output->value->type
23211     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
23212     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
23213     89/<- %edx 0/r32/eax
23214     # if output-type not an addr, abort
23215     (mu-addr-type? %edx)  # => eax
23216     3d/compare-eax-and 0/imm32/false
23217     0f 84/jump-if-= $check-mu-address-stmt:error-output-not-address/disp32
23218     # output-type = output-type->right
23219     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
23220     # if output-type->right is null, output-type = output-type->left
23221     81 7/subop/compare *(eax+0xc) 0/imm32  # Type-tree-right
23222     {
23223       75/jump-if-!= break/disp8
23224       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
23225     }
23226     89/<- %edx 0/r32/eax
23227     # var inout-type/ecx: (addr type-tree) = inout->value->type
23228     (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
23229     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
23230     89/<- %ecx 0/r32/eax
23231     # if (inout->is-deref?) inout-type = inout-type->payload
23232     8b/-> *(esi+0x10) 0/r32/eax  # Stmt-var-is-deref
23233     3d/compare-eax-and 0/imm32/false
23234     {
23235       74/jump-if-= break/disp8
23236       (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
23237       # if inout-type->right is null, t = inout-type->left
23238       81 7/subop/compare *(eax+0xc) 0/imm32  # Type-tree-right
23239       {
23240         75/jump-if-!= break/disp8
23241         (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
23242       }
23243       89/<- %ecx 0/r32/eax
23244     }
23245     # if (inout-type != output-type) abort
23246     (type-equal-ignoring-capacity? %edx %ecx)  # => eax
23247     3d/compare-eax-and 0/imm32
23248     0f 84/jump-if-= $check-mu-address-stmt:error-type-mismatch/disp32
23249 $check-mu-address-stmt:end:
23250     # . restore registers
23251     5f/pop-to-edi
23252     5e/pop-to-esi
23253     5a/pop-to-edx
23254     59/pop-to-ecx
23255     58/pop-to-eax
23256     # . epilogue
23257     89/<- %esp 5/r32/ebp
23258     5d/pop-to-ebp
23259     c3/return
23261 $check-mu-address-stmt:error-no-inout:
23262     (write-buffered *(ebp+0x10) "fn ")
23263     8b/-> *(ebp+0xc) 0/r32/eax
23264     (lookup *eax *(eax+4))  # Function-name Function-name => eax
23265     (write-buffered *(ebp+0x10) %eax)
23266     (write-buffered *(ebp+0x10) ": stmt 'address' expects an inout\n")
23267     (flush *(ebp+0x10))
23268     (stop *(ebp+0x14) 1)
23269     # never gets here
23271 $check-mu-address-stmt:error-too-many-inouts:
23272     (write-buffered *(ebp+0x10) "fn ")
23273     8b/-> *(ebp+0xc) 0/r32/eax
23274     (lookup *eax *(eax+4))  # Function-name Function-name => eax
23275     (write-buffered *(ebp+0x10) %eax)
23276     (write-buffered *(ebp+0x10) ": stmt 'address' must have just one inout\n")
23277     (flush *(ebp+0x10))
23278     (stop *(ebp+0x14) 1)
23279     # never gets here
23281 $check-mu-address-stmt:error-no-output:
23282     (write-buffered *(ebp+0x10) "fn ")
23283     8b/-> *(ebp+0xc) 0/r32/eax
23284     (lookup *eax *(eax+4))  # Function-name Function-name => eax
23285     (write-buffered *(ebp+0x10) %eax)
23286     (write-buffered *(ebp+0x10) ": stmt 'address' expects an output\n")
23287     (flush *(ebp+0x10))
23288     (stop *(ebp+0x14) 1)
23289     # never gets here
23291 $check-mu-address-stmt:error-output-not-in-register:
23292     (write-buffered *(ebp+0x10) "fn ")
23293     8b/-> *(ebp+0xc) 0/r32/eax
23294     (lookup *eax *(eax+4))  # Function-name Function-name => eax
23295     (write-buffered *(ebp+0x10) %eax)
23296     (write-buffered *(ebp+0x10) ": stmt address: output '")
23297     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
23298     (lookup *eax *(eax+4))  # Var-name Var-name => eax
23299     (write-buffered *(ebp+0x10) %eax)
23300     (write-buffered *(ebp+0x10) "' not in a register\n")
23301     (flush *(ebp+0x10))
23302     (stop *(ebp+0x14) 1)
23303     # never gets here
23305 $check-mu-address-stmt:error-too-many-outputs:
23306     (write-buffered *(ebp+0x10) "fn ")
23307     8b/-> *(ebp+0xc) 0/r32/eax
23308     (lookup *eax *(eax+4))  # Function-name Function-name => eax
23309     (write-buffered *(ebp+0x10) %eax)
23310     (write-buffered *(ebp+0x10) ": stmt 'address' must have just one output\n")
23311     (flush *(ebp+0x10))
23312     (stop *(ebp+0x14) 1)
23313     # never gets here
23315 $check-mu-address-stmt:error-output-not-address:
23316     (write-buffered *(ebp+0x10) "fn ")
23317     8b/-> *(ebp+0xc) 0/r32/eax
23318     (lookup *eax *(eax+4))  # Function-name Function-name => eax
23319     (write-buffered *(ebp+0x10) %eax)
23320     (write-buffered *(ebp+0x10) ": stmt address: output '")
23321     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
23322     (lookup *eax *(eax+4))  # Var-name Var-name => eax
23323     (write-buffered *(ebp+0x10) %eax)
23324     (write-buffered *(ebp+0x10) "' is not an addr\n")
23325     (flush *(ebp+0x10))
23326     (stop *(ebp+0x14) 1)
23327     # never gets here
23329 $check-mu-address-stmt:error-type-mismatch:
23330     (write-buffered *(ebp+0x10) "fn ")
23331     8b/-> *(ebp+0xc) 0/r32/eax
23332     (lookup *eax *(eax+4))  # Function-name Function-name => eax
23333     (write-buffered *(ebp+0x10) %eax)
23334     (write-buffered *(ebp+0x10) ": stmt address: output '")
23335     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
23336     (lookup *eax *(eax+4))  # Var-name Var-name => eax
23337     (write-buffered *(ebp+0x10) %eax)
23338     (write-buffered *(ebp+0x10) "' cannot hold address of '")
23339     (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
23340     (lookup *eax *(eax+4))  # Var-name Var-name => eax
23341     (write-buffered *(ebp+0x10) %eax)
23342     (write-buffered *(ebp+0x10) "'\n")
23343     (flush *(ebp+0x10))
23344     (stop *(ebp+0x14) 1)
23345     # never gets here
23347 type-equal-ignoring-capacity?:  # a: (addr type-tree), b: (addr type-tree) -> result/eax: boolean
23348     # . prologue
23349     55/push-ebp
23350     89/<- %ebp 4/r32/esp
23351     # . save registers
23352     51/push-ecx
23353     52/push-edx
23354     53/push-ebx
23355     # var curr-a/ecx: (addr type-tree) = a
23356     8b/-> *(ebp+8) 1/r32/ecx
23357     # var curr-b/ebx: (addr type-tree) = b
23358     8b/-> *(ebp+0xc) 3/r32/ebx
23359     # if (curr-a->is-atom?) fall back to regular equality
23360     81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
23361     0f 85/jump-if-!= $type-equal-ignoring-capacity?:base-case/disp32
23362     # if (curr-a->left != curr-b->left) return false
23363     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
23364     89/<- %edx 0/r32/eax
23365     (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
23366     (type-equal? %edx %eax)  # => eax
23367     3d/compare-eax-and 0/imm32/false
23368     0f 84/jump-if-= $type-equal-ignoring-capacity?:end/disp32  # eax switches meaning
23369     # if (curr-a->left == "array") curr-a = curr-a->element-type
23370     {
23371       (mu-array? %edx)  # => eax
23372       3d/compare-eax-and 0/imm32/false
23373       75/jump-if-!= break/disp8
23374 $type-equal-ignoring-capacity?:array:
23375       # curr-a = curr-a->right->left
23376       (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
23377       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
23378       89/<- %ecx 0/r32/eax
23379       # curr-b = curr-b->right->left
23380       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
23381       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
23382       89/<- %ebx 0/r32/eax
23383       eb/jump $type-equal-ignoring-capacity?:base-case/disp8
23384     }
23385     # if (curr-a->left == "stream") curr-a = curr-a->element-type
23386     {
23387       (mu-stream? %edx)  # => eax
23388       3d/compare-eax-and 0/imm32/false
23389       75/jump-if-!= break/disp8
23390 $type-equal-ignoring-capacity?:stream:
23391       # curr-a = curr-a->right->left
23392       (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
23393       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
23394       89/<- %ecx 0/r32/eax
23395       # curr-b = curr-b->right->left
23396       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
23397       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
23398       89/<- %ebx 0/r32/eax
23399       eb/jump $type-equal-ignoring-capacity?:base-case/disp8
23400     }
23401 $type-equal-ignoring-capacity?:base-case:
23402     # return type-equal?(curr-a, curr-b)
23403     (type-equal? %ecx %ebx)  # => eax
23404 $type-equal-ignoring-capacity?:end:
23405     # . restore registers
23406     5b/pop-to-ebx
23407     5a/pop-to-edx
23408     59/pop-to-ecx
23409     # . epilogue
23410     89/<- %esp 5/r32/ebp
23411     5d/pop-to-ebp
23412     c3/return
23414 check-mu-return-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
23415     # . prologue
23416     55/push-ebp
23417     89/<- %ebp 4/r32/esp
23418     # . save registers
23419     50/push-eax
23420     51/push-ecx
23421     52/push-edx
23422     53/push-ebx
23423     56/push-esi
23424     57/push-edi
23425     # var type-parameters/edx: (addr table (handle array byte) (addr type-tree) 8)
23426     81 5/subop/subtract %esp 0x60/imm32
23427     68/push 0x60/imm32/size
23428     68/push 0/imm32/read
23429     68/push 0/imm32/write
23430     89/<- %edx 4/r32/esp
23431     # var template/esi: (addr list var) = fn->outputs
23432     8b/-> *(ebp+0xc) 0/r32/eax
23433     (lookup *(eax+0x10) *(eax+0x14))  # Function-outputs Function-outputs => eax
23434     89/<- %esi 0/r32/eax
23435     # var curr-template/ebx: (addr list var) = fn->outputs
23436     89/<- %ebx 0/r32/eax
23437     # var curr/edi: (addr stmt-var) = stmt->inouts
23438     8b/-> *(ebp+8) 0/r32/eax
23439     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
23440     89/<- %edi 0/r32/eax
23441     {
23442       # if template is null, break
23443       81 7/subop/compare %ebx 0/imm32
23444       0f 84/jump-if-= break/disp32
23445       # if curr is null, abort
23446       81 7/subop/compare %edi 0/imm32
23447       0f 84/jump-if-= $check-mu-return-stmt:error-too-few-inouts/disp32
23448       # var template-type/ecx: (addr type-tree) = template->value->type
23449       (lookup *ebx *(ebx+4))  # List-value List-value => eax
23450       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
23451       89/<- %ecx 0/r32/eax
23452       # var curr-type/eax: (addr type-tree) = curr->value->type
23453       (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
23454       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
23455       # if (curr->is-deref?) curr-type = payload of curr-type
23456       81 7/subop/compare *(edi+0x10) 0/imm32/false  # Stmt-var-is-deref
23457       {
23458         74/jump-if-= break/disp8
23459         (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
23460         # if t->right is null, t = t->left
23461         81 7/subop/compare *(eax+0xc) 0/imm32  # Type-tree-right
23462         75/jump-if-!= break/disp8
23463         (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
23464       }
23465       # if curr-type is literal and template-type is float, abort
23466       50/push-eax
23467       {
23468         (simple-mu-type? %eax 0)  # literal => eax
23469         3d/compare-eax-and 0/imm32/false
23470         74/jump-if-= break/disp8
23471         (simple-mu-type? %ecx 0xf)  # float => eax
23472         3d/compare-eax-and 0/imm32/false
23473         0f 85/jump-if-!= $check-mu-return-stmt:error-literal-to-float/disp32
23474       }
23475       58/pop-to-eax
23476       # if (curr-type != template-type) abort
23477       (type-match? %ecx %eax %edx)  # => eax
23478       3d/compare-eax-and 0/imm32/false
23479       0f 84/jump-if-= $check-mu-return-stmt:error1/disp32
23480       # if register-within-list-with-conflict?(curr, original template, curr-template, stmt) abort
23481       (register-within-list-with-conflict? %edi %esi %ebx *(ebp+8))  # => eax
23482       3d/compare-eax-and 0/imm32/false
23483       0f 85/jump-if-!= $check-mu-return-stmt:error2/disp32
23484       # template = template->next
23485       (lookup *(ebx+8) *(ebx+0xc))  # List-next List-next => eax
23486       89/<- %ebx 0/r32/eax
23487       # curr = curr->next
23488       (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
23489       89/<- %edi 0/r32/eax
23490       #
23491       e9/jump loop/disp32
23492     }
23493     # if curr is not null, abort
23494     81 7/subop/compare %edi 0/imm32
23495     0f 85/jump-if-!= $check-mu-return-stmt:error-too-many-inouts/disp32
23496 $check-mu-return-stmt:end:
23497     # . reclaim locals
23498     81 0/subop/add %esp 0x6c/imm32
23499     # . restore registers
23500     5f/pop-to-edi
23501     5e/pop-to-esi
23502     5b/pop-to-ebx
23503     5a/pop-to-edx
23504     59/pop-to-ecx
23505     58/pop-to-eax
23506     # . epilogue
23507     89/<- %esp 5/r32/ebp
23508     5d/pop-to-ebp
23509     c3/return
23511 $check-mu-return-stmt:error1:
23512     (write-buffered *(ebp+0x10) "fn ")
23513     8b/-> *(ebp+0xc) 0/r32/eax
23514     (lookup *eax *(eax+4))  # Function-name Function-name => eax
23515     (write-buffered *(ebp+0x10) %eax)
23516     (write-buffered *(ebp+0x10) ": return: '")
23517     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
23518     (lookup *eax *(eax+4))  # Var-name Var-name => eax
23519     (write-buffered *(ebp+0x10) %eax)
23520     (write-buffered *(ebp+0x10) "' has the wrong type\n")
23521     (flush *(ebp+0x10))
23522     (stop *(ebp+0x14) 1)
23523     # never gets here
23525 $check-mu-return-stmt:error2:
23526     (write-buffered *(ebp+0x10) "fn ")
23527     8b/-> *(ebp+0xc) 0/r32/eax
23528     (lookup *eax *(eax+4))  # Function-name Function-name => eax
23529     (write-buffered *(ebp+0x10) %eax)
23530     (write-buffered *(ebp+0x10) ": return: '")
23531     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
23532     (lookup *eax *(eax+4))  # Var-name Var-name => eax
23533     (write-buffered *(ebp+0x10) %eax)
23534     (write-buffered *(ebp+0x10) "' is no longer available\n")
23535     (flush *(ebp+0x10))
23536     (stop *(ebp+0x14) 1)
23537     # never gets here
23539 $check-mu-return-stmt:error-literal-to-float:
23540     (write-buffered *(ebp+0x10) "fn ")
23541     8b/-> *(ebp+0xc) 0/r32/eax
23542     (lookup *eax *(eax+4))  # Function-name Function-name => eax
23543     (write-buffered *(ebp+0x10) %eax)
23544     (write-buffered *(ebp+0x10) ": return: cannot copy literal '")
23545     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
23546     (lookup *eax *(eax+4))  # Var-name Var-name => eax
23547     (write-buffered *(ebp+0x10) %eax)
23548     (write-buffered *(ebp+0x10) "' to float\n")
23549     (flush *(ebp+0x10))
23550     (stop *(ebp+0x14) 1)
23551     # never gets here
23553 $check-mu-return-stmt:error-too-few-inouts:
23554     (write-buffered *(ebp+0x10) "fn ")
23555     8b/-> *(ebp+0xc) 0/r32/eax
23556     (lookup *eax *(eax+4))  # Function-name Function-name => eax
23557     (write-buffered *(ebp+0x10) %eax)
23558     (write-buffered *(ebp+0x10) ": return: too few inouts\n")
23559     (flush *(ebp+0x10))
23560     (stop *(ebp+0x14) 1)
23561     # never gets here
23563 $check-mu-return-stmt:error-too-many-inouts:
23564     (write-buffered *(ebp+0x10) "fn ")
23565     8b/-> *(ebp+0xc) 0/r32/eax
23566     (lookup *eax *(eax+4))  # Function-name Function-name => eax
23567     (write-buffered *(ebp+0x10) %eax)
23568     (write-buffered *(ebp+0x10) ": return: too many inouts\n")
23569     (flush *(ebp+0x10))
23570     (stop *(ebp+0x14) 1)
23571     # never gets here
23573 check-all-unique-registers:  # outputs: (addr list var), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
23574     # . prologue
23575     55/push-ebp
23576     89/<- %ebp 4/r32/esp
23577     # . save registers
23578     50/push-eax
23579     51/push-ecx
23580     56/push-esi
23581     # var table/esi: (addr table (handle array byte) int 8)
23582     81 5/subop/subtract %esp 0x60/imm32
23583     68/push 0x60/imm32/size
23584     68/push 0/imm32/read
23585     68/push 0/imm32/write
23586     89/<- %esi 4/r32/esp
23587     # var curr/ecx: (addr list var) = outputs
23588     8b/-> *(ebp+8) 1/r32/ecx
23589     {
23590       # if (curr == 0) break
23591       81 7/subop/compare %ecx 0/imm32
23592       0f 84/jump-if-= break/disp32
23593       # var reg/eax: (addr array byte) = curr->value->register  # guaranteed to exist
23594       (lookup *ecx *(ecx+4))  # List-value List-value => eax
23595       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
23596       # if reg exists in table, abort
23597       (maybe-get %esi %eax 0xc)  # => eax
23598       3d/compare-eax-and 0/imm32
23599       0f 85/jump-if-!= $check-all-unique-registers:abort/disp32
23600       # insert reg in table
23601       (lookup *ecx *(ecx+4))  # List-value List-value => eax
23602       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
23603       (get-or-insert %esi %eax 0xc Heap)
23604       # curr = curr->next
23605       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
23606       89/<- %ecx 0/r32/eax
23607       e9/jump loop/disp32
23608     }
23609 $check-all-unique-registers:end:
23610     # . reclaim locals
23611     81 0/subop/add %esp 0x6c/imm32
23612     # . restore registers
23613     5e/pop-to-esi
23614     59/pop-to-ecx
23615     58/pop-to-eax
23616     # . epilogue
23617     89/<- %esp 5/r32/ebp
23618     5d/pop-to-ebp
23619     c3/return
23621 $check-all-unique-registers:abort:
23622     (write-buffered *(ebp+0x10) "fn ")
23623     8b/-> *(ebp+0xc) 0/r32/eax
23624     (lookup *eax *(eax+4))  # Function-name Function-name => eax
23625     (write-buffered *(ebp+0x10) %eax)
23626     (write-buffered *(ebp+0x10) ": outputs must be in unique registers\n")
23627     (flush *(ebp+0x10))
23628     (stop *(ebp+0x14) 1)
23629     # never gets here
23631 # return false if s's register is not between start (inclusive) and end (exclusive)
23632 # return false if the positionally corresponding register in stmt->inouts (where s comes from) is also s's register
23633 # otherwise return true
23634 register-within-list-with-conflict?:  # s: (addr stmt-var), start: (addr list var), end: (addr list var), stmt: (addr stmt) -> result/eax: boolean
23635     # . prologue
23636     55/push-ebp
23637     89/<- %ebp 4/r32/esp
23638     # . save registers
23639     51/push-ecx
23640     52/push-edx
23641     53/push-ebx
23642     56/push-esi
23643     57/push-edi
23644     # var target/ebx: (addr array byte) = s->value->register
23645     8b/-> *(ebp+8) 0/r32/eax
23646     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
23647     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
23648 #?     (write-buffered Stderr "AA: ")
23649 #?     (write-buffered Stderr %eax)
23650 #?     (write-buffered Stderr Newline)
23651 #?     (flush Stderr)
23652     # if (var->register == 0) return false
23653     3d/compare-eax-and 0/imm32
23654     0f 84/jump-if-= $register-within-list-with-conflict?:end/disp32  # eax turns into result
23655     89/<- %ebx 0/r32/eax
23656     # var curr/ecx: (addr list var) = start
23657     8b/-> *(ebp+0xc) 1/r32/ecx
23658     # edx = end
23659     8b/-> *(ebp+0x10) 2/r32/edx
23660     {
23661       # if (curr == 0) break
23662       81 7/subop/compare %edi 0/imm32
23663       0f 84/jump-if-= break/disp32
23664       # if (curr == end) break
23665       39/compare %ecx 2/r32/edx
23666       0f 84/jump-if-= break/disp32
23667       # var curr-reg/eax: (addr array byte) = curr->value->register
23668       (lookup *ecx *(ecx+4))  # List-value List-value => eax
23669       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
23670       # if (curr-reg == 0) continue
23671       3d/compare-eax-and 0/imm32
23672       74/jump-if-= $register-within-list-with-conflict?:continue/disp8
23673       # if (curr-reg == target) check for conflict
23674       (string-equal? %eax %ebx)  # => eax
23675       3d/compare-eax-and 0/imm32/false
23676       {
23677         74/jump-if-= break/disp8
23678 #?         (write-buffered Stderr "conflict?\n")
23679 #?         (flush Stderr)
23680         # var return-inouts/eax: (addr stmt-var) = stmt->inouts
23681         8b/-> *(ebp+0x14) 0/r32/eax
23682         (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
23683         (register-conflict? %ebx %eax *(ebp+0xc))  # => eax
23684         eb/jump $register-within-list-with-conflict?:end/disp8
23685       }
23686 $register-within-list-with-conflict?:continue:
23687       # curr = curr->next
23688       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
23689       89/<- %ecx 0/r32/eax
23690       e9/jump loop/disp32
23691     }
23692     # return false
23693     b8/copy-to-eax 0/imm32/false
23694 $register-within-list-with-conflict?:end:
23695     # . restore registers
23696     5f/pop-to-edi
23697     5e/pop-to-esi
23698     5b/pop-to-ebx
23699     5a/pop-to-edx
23700     59/pop-to-ecx
23701     # . epilogue
23702     89/<- %esp 5/r32/ebp
23703     5d/pop-to-ebp
23704     c3/return
23706 # At the first occurrence of register 'reg' in fn-outputs,
23707 # check if the corresponding element of return-inouts has a different register.
23708 # This hacky helper is intended to be called in one specific place. Don't
23709 # reuse it as is.
23710 register-conflict?:  # reg: (addr array byte), return-inouts: (addr stmt-var), fn-outputs: (addr list var) => result/eax: boolean
23711     # . prologue
23712     55/push-ebp
23713     89/<- %ebp 4/r32/esp
23714     # . save registers
23715     51/push-ecx
23716     52/push-edx
23717     53/push-ebx
23718     56/push-esi
23719     57/push-edi
23720 #?     (write-buffered Stderr "BB: ")
23721 #?     (write-buffered Stderr *(ebp+8))
23722 #?     (write-buffered Stderr Newline)
23723 #?     (flush Stderr)
23724     # var curr-output/edi: (addr list var) = fn-outputs
23725     8b/-> *(ebp+0x10) 7/r32/edi
23726     # var curr-inout/esi: (addr stmt-var) = return-inouts
23727     8b/-> *(ebp+0xc) 6/r32/esi
23728     {
23729       # if (curr-output == 0) abort
23730       81 7/subop/compare %edi 0/imm32
23731       0f 84/jump-if-= break/disp32
23732       # if (curr-output->value->register != reg) continue
23733       (lookup *edi *(edi+4))  # List-value List-value => eax
23734       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
23735       (string-equal? %eax *(ebp+8))  # => eax
23736       3d/compare-eax-and 0/imm32/false
23737       0f 84/jump-if= $register-conflict?:continue/disp32
23738 #?       (write-buffered Stderr "rescan\n")
23739 #?       (flush Stderr)
23740       # var curr-reg/eax: (addr array byte) = curr-inout->value->register
23741       (lookup *esi *(esi+4))  # List-value List-value => eax
23742       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
23743       # if (curr-reg == 0) return true
23744       3d/compare-eax-and 0/imm32
23745       {
23746         75/jump-if-!= break/disp8
23747 #?         (write-buffered Stderr "no register\n")
23748 #?         (flush Stderr)
23749         b8/copy-to-eax 1/imm32/true
23750         e9/jump $register-conflict?:end/disp32
23751       }
23752       # return (curr-reg != reg)
23753       (string-equal? %eax *(ebp+8))  # => eax
23754       3d/compare-eax-and 0/imm32/false
23755       0f 94/set-if-= %al
23756 #?       (write-buffered Stderr "final: ")
23757 #?       (write-int32-hex-buffered Stderr %eax)
23758 #?       (write-buffered Stderr Newline)
23759 #?       (flush Stderr)
23760       eb/jump $register-conflict?:end/disp8
23761 $register-conflict?:continue:
23762       # curr-output = curr-output->next
23763       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
23764       89/<- %edi 0/r32/eax
23765       # curr-inout = curr-inout->next
23766       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
23767       89/<- %esi 0/r32/eax
23768       e9/jump loop/disp32
23769     }
23770     # should never get here
23771     (write-buffered Stderr "register-conflict? misused\n")
23772     (flush Stderr)
23773     e8/call syscall_exit/disp32
23774 $register-conflict?:end:
23775     # . restore registers
23776     5f/pop-to-edi
23777     5e/pop-to-esi
23778     5b/pop-to-ebx
23779     5a/pop-to-edx
23780     59/pop-to-ecx
23781     # . epilogue
23782     89/<- %esp 5/r32/ebp
23783     5d/pop-to-ebp
23784     c3/return
23786 check-final-stmt-is-return:  # block: (addr block), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
23787     # . prologue
23788     55/push-ebp
23789     89/<- %ebp 4/r32/esp
23790     # . save registers
23791     50/push-eax
23792     51/push-ecx
23793     # var curr/ecx: (addr list stmt) = block->stmts
23794     8b/-> *(ebp+8) 0/r32/eax
23795     (lookup *(eax+4) *(eax+8))  # Block-stmts Block-stmts => eax
23796     3d/compare-eax-and 0/imm32
23797     74/jump-if-= $check-final-stmt-is-return:error/disp8
23798     89/<- %ecx 0/r32/eax
23799     {
23800       # if curr->next == 0, break
23801       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
23802       3d/compare-eax-and 0/imm32
23803       74/jump-if-= break/disp8
23804       # curr = curr->next
23805       89/<- %ecx 0/r32/eax
23806       e9/jump loop/disp32
23807     }
23808 $check-final-stmt-is-return:check-tag:
23809     # if curr->value->tag != Stmt1, abort
23810     (lookup *ecx *(ecx+4))  # List-value List-value => eax
23811     81 7/subop/compare *eax 1/imm32/stmt1  # Stmt-tag
23812     75/jump-if-!= $check-final-stmt-is-return:error/disp8
23813 $check-final-stmt-is-return:check-operation:
23814     # if curr->operation != "return", abort
23815     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
23816     (string-equal? %eax "return")
23817     3d/compare-eax-and 0/imm32/false
23818     74/jump-if-= $check-final-stmt-is-return:error/disp8
23819 $check-final-stmt-is-return:end:
23820     # . restore registers
23821     59/pop-to-ecx
23822     58/pop-to-eax
23823     # . epilogue
23824     89/<- %esp 5/r32/ebp
23825     5d/pop-to-ebp
23826     c3/return
23828 $check-final-stmt-is-return:error:
23829     (write-buffered *(ebp+0x10) "fn ")
23830     8b/-> *(ebp+0xc) 0/r32/eax
23831     (lookup *eax *(eax+4))  # Function-name Function-name => eax
23832     (write-buffered *(ebp+0x10) %eax)
23833     (write-buffered *(ebp+0x10) ": final statement should be a 'return'\n")
23834     (flush *(ebp+0x10))
23835     (stop *(ebp+0x14) 1)
23836     # never gets here
23838 check-no-breaks:  # block: (addr block), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
23839     # . prologue
23840     55/push-ebp
23841     89/<- %ebp 4/r32/esp
23842     # . save registers
23843     50/push-eax
23844     51/push-ecx
23845     # var curr/ecx: (addr list stmt) = block->stmts
23846     8b/-> *(ebp+8) 0/r32/eax
23847     (lookup *(eax+4) *(eax+8))  # Block-stmts Block-stmts => eax
23848     3d/compare-eax-and 0/imm32
23849     0f 84/jump-if-= $check-no-breaks:end/disp32
23850     89/<- %ecx 0/r32/eax
23851     {
23852       # if curr->next == 0, break
23853       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
23854       3d/compare-eax-and 0/imm32
23855       74/jump-if-= break/disp8
23856       # if curr->value->tag != Stmt1, continue
23857       (lookup *ecx *(ecx+4))  # List-value List-value => eax
23858       81 7/subop/compare *eax 1/imm32/stmt1  # Stmt-tag
23859       75/jump-if-!= $check-no-breaks:continue/disp8
23860       # if curr->value->operation starts with "break", abort
23861       (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
23862       (string-starts-with? %eax "break")  # => eax
23863       3d/compare-eax-and 0/imm32/false
23864       75/jump-if-!= $check-no-breaks:error/disp8
23865 $check-no-breaks:continue:
23866       # curr = curr->next
23867       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
23868       89/<- %ecx 0/r32/eax
23869       e9/jump loop/disp32
23870     }
23871 $check-no-breaks:end:
23872     # . restore registers
23873     59/pop-to-ecx
23874     58/pop-to-eax
23875     # . epilogue
23876     89/<- %esp 5/r32/ebp
23877     5d/pop-to-ebp
23878     c3/return
23880 $check-no-breaks:error:
23881     (write-buffered *(ebp+0x10) "fn ")
23882     8b/-> *(ebp+0xc) 0/r32/eax
23883     (lookup *eax *(eax+4))  # Function-name Function-name => eax
23884     (write-buffered *(ebp+0x10) %eax)
23885     (write-buffered *(ebp+0x10) " has outputs, so you cannot 'break' out of the outermost block. Use 'return'.\n")
23886     (flush *(ebp+0x10))
23887     (stop *(ebp+0x14) 1)
23888     # never gets here
23890 check-mu-get-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
23891     # . prologue
23892     55/push-ebp
23893     89/<- %ebp 4/r32/esp
23894     # . save registers
23895     50/push-eax
23896     51/push-ecx
23897     52/push-edx
23898     53/push-ebx
23899     56/push-esi
23900     57/push-edi
23901     # esi = stmt
23902     8b/-> *(ebp+8) 6/r32/esi
23903     # - check for 0 inouts
23904     # var base/ecx: (addr var) = stmt->inouts->value
23905     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
23906     3d/compare-eax-and 0/imm32/false
23907     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-inouts/disp32
23908     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
23909     89/<- %ecx 0/r32/eax
23910 $check-mu-get-stmt:check-base:
23911     # - check base type
23912     # if it's an 'addr', check that it's in a register
23913     # var base-type/ebx: (addr type-tree) = lookup(base->type)
23914     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
23915     89/<- %ebx 0/r32/eax
23916     {
23917       81 7/subop/compare *ebx 0/imm32/false  # Type-tree-is-atom
23918       0f 85/jump-if-!= break/disp32
23919 $check-mu-get-stmt:base-is-compound:
23920       # if (type->left != addr) break
23921       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
23922       (simple-mu-type? %eax 2)  # addr => eax
23923       3d/compare-eax-and 0/imm32/false
23924       74/jump-if-= break/disp8
23925 $check-mu-get-stmt:base-is-addr:
23926       # now check for register
23927       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
23928       0f 84/jump-if-= $check-mu-get-stmt:error-base-type-addr-but-not-register/disp32
23929 $check-mu-get-stmt:base-is-addr-in-register:
23930       # type->left is now an addr; skip it
23931       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
23932       81 7/subop/compare *(eax+0xc) 0/imm32  # Type-tree-right
23933       0f 85/jump-if-!= $check-mu-get-stmt:error-bad-base/disp32
23934 $check-mu-get-stmt:base-is-addr-to-atom-in-register:
23935       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
23936       89/<- %ebx 0/r32/eax
23937     }
23938 $check-mu-get-stmt:check-base-typeinfo:
23939     # ensure type is a container
23940     81 7/subop/compare *ebx 0/imm32/false  # Type-tree-is-atom
23941     {
23942       75/jump-if-!= break/disp8
23943       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
23944       89/<- %ebx 0/r32/eax
23945     }
23946     # var base-type-id/ebx: type-id = base-type->value
23947     8b/-> *(ebx+4) 3/r32/ebx  # Type-tree-value
23948     (container? %ebx)  # => eax
23949     3d/compare-eax-and 0/imm32/false
23950     0f 84/jump-if-= $check-mu-get-stmt:error-bad-base/disp32
23951     # var base-typeinfo/edx: (addr typeinfo) = find-typeinfo(base-type-id)
23952     # . var container/ecx: (handle typeinfo)
23953     68/push 0/imm32
23954     68/push 0/imm32
23955     89/<- %ecx 4/r32/esp
23956     # .
23957     (find-typeinfo %ebx %ecx)
23958     (lookup *ecx *(ecx+4))  # => eax
23959     # . reclaim container
23960     81 0/subop/add %esp 8/imm32
23961     # .
23962     89/<- %edx 0/r32/eax
23963     # var offset/ecx: (addr stmt-var) = stmt->inouts->next
23964     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
23965     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
23966     89/<- %ecx 0/r32/eax
23967     # - check for 1 inout
23968     3d/compare-eax-and 0/imm32/false
23969     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-inouts/disp32
23970     # var offset/ecx: (addr var) = lookup(offset->value)
23971     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
23972     89/<- %ecx 0/r32/eax
23973     # - check for valid field
23974     81 7/subop/compare *(ecx+0x14) -1/imm32/uninitialized  # Var-offset
23975     0f 84/jump-if-= $check-mu-get-stmt:error-bad-field/disp32
23976     # - check for too many inouts
23977     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
23978     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
23979     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
23980     3d/compare-eax-and 0/imm32/false
23981     0f 85/jump-if-!= $check-mu-get-stmt:error-too-many-inouts/disp32
23982     # var output/edi: (addr var) = stmt->outputs->value
23983     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
23984     # - check for 0 outputs
23985     3d/compare-eax-and 0/imm32/false
23986     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-outputs/disp32
23987     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
23988     89/<- %edi 0/r32/eax
23989 $check-mu-get-stmt:check-output-type:
23990     # - check output type
23991     # must be in register
23992     (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
23993     3d/compare-eax-and 0/imm32
23994     0f 84/jump-if-= $check-mu-get-stmt:error-output-not-in-register/disp32
23995     # must have a non-atomic type
23996     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
23997     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
23998     0f 85/jump-if-!= $check-mu-get-stmt:error-output-type-not-address/disp32
23999     # type must start with (addr ...)
24000     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
24001     (simple-mu-type? %eax 2)  # => eax
24002     3d/compare-eax-and 0/imm32/false
24003     0f 84/jump-if-= $check-mu-get-stmt:error-output-type-not-address/disp32
24004 $check-mu-get-stmt:check-output-type-match:
24005     # payload of addr type must match 'type' definition
24006     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
24007     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
24008     # if (payload->right == null) payload = payload->left
24009     81 7/subop/compare *(eax+0xc) 0/imm32/null  # Type-tree-right
24010     {
24011       75/jump-if-!= break/disp8
24012       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
24013     }
24014     89/<- %edi 0/r32/eax
24015     # . var output-name/ecx: (addr array byte)
24016     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
24017     89/<- %ecx 0/r32/eax
24018     # . var base-typeinfo-entry/eax: (addr handle typeinfo-entry)
24019     (lookup *(edx+4) *(edx+8))  # Typeinfo-fields Typeinfo-fields => eax
24020     (get %eax %ecx 0x10)  # => eax
24021     # .
24022     (lookup *eax *(eax+4))  # => eax
24023     (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
24024     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
24025     # .
24026     (type-equal? %edi %eax)  # => eax
24027     3d/compare-eax-and 0/imm32/false
24028     0f 84/jump-if-= $check-mu-get-stmt:error-bad-output-type/disp32
24029     # - check for too many outputs
24030     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
24031     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
24032     3d/compare-eax-and 0/imm32/false
24033     0f 85/jump-if-!= $check-mu-get-stmt:error-too-many-outputs/disp32
24034 $check-mu-get-stmt:end:
24035     # . restore registers
24036     5f/pop-to-edi
24037     5e/pop-to-esi
24038     5b/pop-to-ebx
24039     5a/pop-to-edx
24040     59/pop-to-ecx
24041     58/pop-to-eax
24042     # . epilogue
24043     89/<- %esp 5/r32/ebp
24044     5d/pop-to-ebp
24045     c3/return
24047 $check-mu-get-stmt:error-too-few-inouts:
24048     (write-buffered *(ebp+0x10) "fn ")
24049     8b/-> *(ebp+0xc) 0/r32/eax
24050     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24051     (write-buffered *(ebp+0x10) %eax)
24052     (write-buffered *(ebp+0x10) ": stmt get: too few inouts (2 required)\n")
24053     (flush *(ebp+0x10))
24054     (stop *(ebp+0x14) 1)
24055     # never gets here
24057 $check-mu-get-stmt:error-too-many-inouts:
24058     (write-buffered *(ebp+0x10) "fn ")
24059     8b/-> *(ebp+0xc) 0/r32/eax
24060     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24061     (write-buffered *(ebp+0x10) %eax)
24062     (write-buffered *(ebp+0x10) ": stmt get: too many inouts (2 required)\n")
24063     (flush *(ebp+0x10))
24064     (stop *(ebp+0x14) 1)
24065     # never gets here
24067 $check-mu-get-stmt:error-too-few-outputs:
24068     (write-buffered *(ebp+0x10) "fn ")
24069     8b/-> *(ebp+0xc) 0/r32/eax
24070     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24071     (write-buffered *(ebp+0x10) %eax)
24072     (write-buffered *(ebp+0x10) ": stmt get: must have an output\n")
24073     (flush *(ebp+0x10))
24074     (stop *(ebp+0x14) 1)
24075     # never gets here
24077 $check-mu-get-stmt:error-too-many-outputs:
24078     (write-buffered *(ebp+0x10) "fn ")
24079     8b/-> *(ebp+0xc) 0/r32/eax
24080     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24081     (write-buffered *(ebp+0x10) %eax)
24082     (write-buffered *(ebp+0x10) ": stmt get: too many outputs (1 required)\n")
24083     (flush *(ebp+0x10))
24084     (stop *(ebp+0x14) 1)
24085     # never gets here
24087 $check-mu-get-stmt:error-bad-base:
24088     # error("fn " fn ": stmt get: var '" base->name "' must have a 'type' definition\n")
24089     (write-buffered *(ebp+0x10) "fn ")
24090     8b/-> *(ebp+0xc) 0/r32/eax
24091     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24092     (write-buffered *(ebp+0x10) %eax)
24093     (write-buffered *(ebp+0x10) ": stmt get: var '")
24094     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
24095     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
24096     (lookup *eax *(eax+4))  # Var-name Var-name => eax
24097     (write-buffered *(ebp+0x10) %eax)
24098     (write-buffered *(ebp+0x10) "' must have a 'type' definition\n")
24099     (flush *(ebp+0x10))
24100     (stop *(ebp+0x14) 1)
24101     # never gets here
24103 $check-mu-get-stmt:error-base-type-addr-but-not-register:
24104     (write-buffered *(ebp+0x10) "fn ")
24105     8b/-> *(ebp+0xc) 0/r32/eax
24106     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24107     (write-buffered *(ebp+0x10) %eax)
24108     (write-buffered *(ebp+0x10) ": stmt get: var '")
24109     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
24110     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
24111     (lookup *eax *(eax+4))  # Var-name Var-name => eax
24112     (write-buffered *(ebp+0x10) %eax)
24113     (write-buffered *(ebp+0x10) "' is an 'addr' type, and so must live in a register\n")
24114     (flush *(ebp+0x10))
24115     (stop *(ebp+0x14) 1)
24116     # never gets here
24118 $check-mu-get-stmt:error-bad-field:
24119     # error("fn " fn ": stmt get: type " type " has no member called '" curr->name "'\n")
24120     (write-buffered *(ebp+0x10) "fn ")
24121     8b/-> *(ebp+0xc) 0/r32/eax
24122     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24123     (write-buffered *(ebp+0x10) %eax)
24124     (write-buffered *(ebp+0x10) ": stmt get: type '")
24125     # . write(Type-id->data[tmp])
24126     bf/copy-to-edi Type-id/imm32
24127     8b/-> *(edi+ebx<<2+0xc) 6/r32/esi
24128     {
24129       81 7/subop/compare %esi 0/imm32
24130       74/jump-if-= break/disp8
24131       (write-buffered *(ebp+0x10) %esi)
24132     }
24133     # .
24134     (write-buffered *(ebp+0x10) "' has no member called '")
24135     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
24136     (write-buffered *(ebp+0x10) %eax)
24137     (write-buffered *(ebp+0x10) "'\n")
24138     (flush *(ebp+0x10))
24139     (stop *(ebp+0x14) 1)
24140     # never gets here
24142 $check-mu-get-stmt:error-output-not-in-register:
24143     (write-buffered *(ebp+0x10) "fn ")
24144     8b/-> *(ebp+0xc) 0/r32/eax
24145     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24146     (write-buffered *(ebp+0x10) %eax)
24147     (write-buffered *(ebp+0x10) ": stmt get: output '")
24148     (lookup *edi *(edi+4))  # Var-name Var-name => eax
24149     (write-buffered *(ebp+0x10) %eax)
24150     (write-buffered *(ebp+0x10) "' is not in a register\n")
24151     (flush *(ebp+0x10))
24152     (stop *(ebp+0x14) 1)
24153     # never gets here
24155 $check-mu-get-stmt:error-output-type-not-address:
24156     (write-buffered *(ebp+0x10) "fn ")
24157     8b/-> *(ebp+0xc) 0/r32/eax
24158     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24159     (write-buffered *(ebp+0x10) %eax)
24160     (write-buffered *(ebp+0x10) ": stmt get: output must be an addr\n")
24161     (flush *(ebp+0x10))
24162     (stop *(ebp+0x14) 1)
24163     # never gets here
24165 $check-mu-get-stmt:error-bad-output-type:
24166     (write-buffered *(ebp+0x10) "fn ")
24167     8b/-> *(ebp+0xc) 0/r32/eax
24168     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24169     (write-buffered *(ebp+0x10) %eax)
24170     (write-buffered *(ebp+0x10) ": stmt get: wrong output type for member '")
24171     (write-buffered *(ebp+0x10) %ecx)
24172     (write-buffered *(ebp+0x10) "' of type '")
24173     bf/copy-to-edi Type-id/imm32
24174     8b/-> *(edi+ebx<<2+0xc) 6/r32/esi
24175     {
24176       81 7/subop/compare %esi 0/imm32
24177       74/jump-if-= break/disp8
24178       (write-buffered *(ebp+0x10) %esi)
24179     }
24180     (write-buffered *(ebp+0x10) "'\n")
24181     (flush *(ebp+0x10))
24182     (stop *(ebp+0x14) 1)
24183     # never gets here
24185 check-mu-index-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
24186     # . prologue
24187     55/push-ebp
24188     89/<- %ebp 4/r32/esp
24189     # . save registers
24190     50/push-eax
24191     51/push-ecx
24192     52/push-edx
24193     53/push-ebx
24194     56/push-esi
24195     57/push-edi
24196     # esi = stmt
24197     8b/-> *(ebp+8) 6/r32/esi
24198     # - check for 0 inouts
24199     # var base/ecx: (addr var) = stmt->inouts->value
24200     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
24201 $check-mu-index-stmt:check-no-inouts:
24202     3d/compare-eax-and 0/imm32
24203     0f 84/jump-if-= $check-mu-index-stmt:error-too-few-inouts/disp32
24204     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
24205     89/<- %ecx 0/r32/eax
24206     # - check base type is either (addr array ...) in register or (array ...) on stack
24207     # var base-type/ebx: (addr type-tree) = lookup(base->type)
24208     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
24209     89/<- %ebx 0/r32/eax
24210     # if base-type is an atom, abort with a precise error
24211     81 7/subop/compare *ebx 0/imm32/false  # Type-tree-is-atom
24212     {
24213       74/jump-if-= break/disp8
24214       (simple-mu-type? %ebx 3)  # array => eax
24215       3d/compare-eax-and 0/imm32/false
24216       0f 85/jump-if-!= $check-mu-index-stmt:error-base-array-atom-type/disp32
24217       0f 84/jump-if-= $check-mu-index-stmt:error-base-non-array-type/disp32
24218     }
24219 $check-mu-index-stmt:base-is-compound:
24220     # if type->left not addr or array, abort
24221     {
24222       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
24223       (simple-mu-type? %eax 2)  # addr => eax
24224       3d/compare-eax-and 0/imm32/false
24225       75/jump-if-!= break/disp8
24226       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
24227       (simple-mu-type? %eax 3)  # array => eax
24228       3d/compare-eax-and 0/imm32/false
24229       75/jump-if-!= break/disp8
24230       e9/jump $check-mu-index-stmt:error-base-non-array-type/disp32
24231     }
24232     # if (type->left == addr) ensure type->right->left == array and type->register exists
24233     {
24234       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
24235       (simple-mu-type? %eax 2)  # addr => eax
24236       3d/compare-eax-and 0/imm32/false
24237       74/jump-if-= break/disp8
24238 $check-mu-index-stmt:base-is-addr:
24239       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
24240       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
24241       (simple-mu-type? %eax 3)  # array => eax
24242       3d/compare-eax-and 0/imm32/false
24243       0f 84/jump-if-= $check-mu-index-stmt:error-base-non-array-type/disp32
24244 $check-mu-index-stmt:check-base-addr-is-register:
24245       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
24246       0f 84/jump-if-= $check-mu-index-stmt:error-base-address-array-type-on-stack/disp32
24247     }
24248     # if (type->left == array) ensure type->register doesn't exist
24249     {
24250       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
24251       (simple-mu-type? %eax 3)  # array => eax
24252       3d/compare-eax-and 0/imm32/false
24253       74/jump-if-= break/disp8
24254 $check-mu-index-stmt:base-is-array:
24255       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
24256       0f 85/jump-if-!= $check-mu-index-stmt:error-base-array-type-in-register/disp32
24257     }
24258     # if (base-type->left == addr) base-type = base-type->right
24259     {
24260       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
24261       (simple-mu-type? %eax 2)  # addr => eax
24262       3d/compare-eax-and 0/imm32/false
24263       74/jump-if-= break/disp8
24264       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
24265       89/<- %ebx 0/r32/eax
24266     }
24267     # - check for 1 inout
24268     # var index/ecx: (addr stmt-var) = stmt->inouts->next->value
24269     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
24270     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
24271 $check-mu-index-stmt:check-single-inout:
24272     3d/compare-eax-and 0/imm32
24273     0f 84/jump-if-= $check-mu-index-stmt:error-too-few-inouts/disp32
24274     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
24275     89/<- %ecx 0/r32/eax
24276     # - check index is either a literal or register
24277     # var index-type/edx: (addr type-tree)
24278     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
24279     89/<- %edx 0/r32/eax
24280     # if index type is an atom, it must be a literal or int
24281     81 7/subop/compare *edx 0/imm32/false  # Type-tree-is-atom
24282     {
24283       74/jump-if-= break/disp8
24284 $check-mu-index-stmt:index-type-is-atom:
24285       (simple-mu-type? %edx 0)  # literal => eax
24286       3d/compare-eax-and 0/imm32/false
24287       75/jump-if-!= $check-mu-index-stmt:index-type-done/disp8
24288       (simple-mu-type? %edx 1)  # int => eax
24289       3d/compare-eax-and 0/imm32/false
24290       75/jump-if-!= $check-mu-index-stmt:index-type-done/disp8
24291       (simple-mu-type? %edx 7)  # offset => eax
24292       3d/compare-eax-and 0/imm32/false
24293       0f 85/jump-if-!= $check-mu-index-stmt:error-index-offset-atom-type/disp32
24294       e9/jump $check-mu-index-stmt:error-invalid-index-type/disp32
24295     }
24296     # if index type is a non-atom: it must be an offset
24297     {
24298       75/jump-if-!= break/disp8
24299 $check-mu-index-stmt:index-type-is-non-atom:
24300       (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
24301       (simple-mu-type? %eax 7)  # offset => eax
24302       3d/compare-eax-and 0/imm32/false
24303       0f 84/jump-if-= $check-mu-index-stmt:error-invalid-index-type/disp32
24304     }
24305 $check-mu-index-stmt:index-type-done:
24306     # check index is either a literal or in a register
24307     {
24308       (simple-mu-type? %edx 0)  # literal => eax
24309       3d/compare-eax-and 0/imm32/false
24310       75/jump-if-!= break/disp8
24311 $check-mu-index-stmt:check-index-in-register:
24312       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
24313       0f 84/jump-if-= $check-mu-index-stmt:error-index-on-stack/disp32
24314     }
24315     # - if index is an 'int', check that element type of base has size 1, 2, 4 or 8 bytes.
24316     {
24317       (simple-mu-type? %edx 1)  # int => eax
24318       3d/compare-eax-and 0/imm32/false
24319       74/jump-if-= break/disp8
24320 $check-mu-index-stmt:check-index-can-be-int:
24321       (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
24322       (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
24323       (array-element-size %eax)  # => eax
24324       3d/compare-eax-and 1/imm32
24325       74/jump-if-= break/disp8
24326       3d/compare-eax-and 2/imm32
24327       74/jump-if-= break/disp8
24328       3d/compare-eax-and 4/imm32
24329       74/jump-if-= break/disp8
24330       3d/compare-eax-and 8/imm32
24331       74/jump-if-= break/disp8
24332       e9/jump $check-mu-index-stmt:error-index-needs-offset/disp32
24333     }
24334     # - check for too many inouts
24335     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
24336     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
24337     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
24338     3d/compare-eax-and 0/imm32/false
24339     0f 85/jump-if-!= $check-mu-index-stmt:error-too-many-inouts/disp32
24340     # - check for 0 outputs
24341     # var output/edi: (addr var) = stmt->outputs->value
24342     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
24343     3d/compare-eax-and 0/imm32/false
24344     0f 84/jump-if-= $check-mu-index-stmt:error-too-few-outputs/disp32
24345     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
24346     89/<- %edi 0/r32/eax
24347     # - check output type
24348     # must have a non-atomic type
24349     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
24350     89/<- %edx 0/r32/eax
24351     81 7/subop/compare *edx 0/imm32/false  # Type-tree-is-atom
24352     0f 85/jump-if-!= $check-mu-index-stmt:error-output-type-not-address/disp32
24353     # type must start with (addr ...)
24354     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
24355     (simple-mu-type? %eax 2)  # addr => eax
24356     3d/compare-eax-and 0/imm32/false
24357     0f 84/jump-if-= $check-mu-index-stmt:error-output-type-not-address/disp32
24358     # if tail(base-type) != tail(output-type) abort
24359     (type-tail %ebx)  # => eax
24360     89/<- %ebx 0/r32/eax
24361     (type-tail %edx)  # => eax
24362     (type-equal? %ebx %eax)  # => eax
24363     3d/compare-eax-and 0/imm32/false
24364     0f 84/jump-if-= $check-mu-index-stmt:error-bad-output-type/disp32
24365     # - check for too many outputs
24366     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
24367     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
24368     3d/compare-eax-and 0/imm32/false
24369     0f 85/jump-if-!= $check-mu-index-stmt:error-too-many-outputs/disp32
24370 $check-mu-index-stmt:end:
24371     # . restore registers
24372     5f/pop-to-edi
24373     5e/pop-to-esi
24374     5b/pop-to-ebx
24375     5a/pop-to-edx
24376     59/pop-to-ecx
24377     58/pop-to-eax
24378     # . epilogue
24379     89/<- %esp 5/r32/ebp
24380     5d/pop-to-ebp
24381     c3/return
24383 $check-mu-index-stmt:error-base-non-array-type:
24384     (write-buffered *(ebp+0x10) "fn ")
24385     8b/-> *(ebp+0xc) 0/r32/eax
24386     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24387     (write-buffered *(ebp+0x10) %eax)
24388     (write-buffered *(ebp+0x10) ": stmt index: var '")
24389     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
24390     (write-buffered *(ebp+0x10) %eax)
24391     (write-buffered *(ebp+0x10) "' is not an array\n")
24392     (flush *(ebp+0x10))
24393     (stop *(ebp+0x14) 1)
24394     # never gets here
24396 $check-mu-index-stmt:error-base-array-atom-type:
24397     (write-buffered *(ebp+0x10) "fn ")
24398     8b/-> *(ebp+0xc) 0/r32/eax
24399     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24400     (write-buffered *(ebp+0x10) %eax)
24401     (write-buffered *(ebp+0x10) ": stmt index: array '")
24402     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
24403     (write-buffered *(ebp+0x10) %eax)
24404     (write-buffered *(ebp+0x10) "' must specify the type of its elements\n")
24405     (flush *(ebp+0x10))
24406     (stop *(ebp+0x14) 1)
24407     # never gets here
24409 $check-mu-index-stmt:error-base-address-array-type-on-stack:
24410     (write-buffered *(ebp+0x10) "fn ")
24411     8b/-> *(ebp+0xc) 0/r32/eax
24412     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24413     (write-buffered *(ebp+0x10) %eax)
24414     (write-buffered *(ebp+0x10) ": stmt index: var '")
24415     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
24416     (write-buffered *(ebp+0x10) %eax)
24417     (write-buffered *(ebp+0x10) "' is an addr to an array, and so must live in a register\n")
24418     (flush *(ebp+0x10))
24419     (stop *(ebp+0x14) 1)
24420     # never gets here
24422 $check-mu-index-stmt:error-base-array-type-in-register:
24423     (write-buffered *(ebp+0x10) "fn ")
24424     8b/-> *(ebp+0xc) 0/r32/eax
24425     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24426     (write-buffered *(ebp+0x10) %eax)
24427     (write-buffered *(ebp+0x10) ": stmt index: var '")
24428     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
24429     (write-buffered *(ebp+0x10) %eax)
24430     (write-buffered *(ebp+0x10) "' is an array, and so must live on the stack\n")
24431     (flush *(ebp+0x10))
24432     (stop *(ebp+0x14) 1)
24433     # never gets here
24435 $check-mu-index-stmt:error-too-few-inouts:
24436     (write-buffered *(ebp+0x10) "fn ")
24437     8b/-> *(ebp+0xc) 0/r32/eax
24438     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24439     (write-buffered *(ebp+0x10) %eax)
24440     (write-buffered *(ebp+0x10) ": stmt index: too few inouts (2 required)\n")
24441     (flush *(ebp+0x10))
24442     (stop *(ebp+0x14) 1)
24443     # never gets here
24445 $check-mu-index-stmt:error-invalid-index-type:
24446     (write-buffered *(ebp+0x10) "fn ")
24447     8b/-> *(ebp+0xc) 0/r32/eax
24448     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24449     (write-buffered *(ebp+0x10) %eax)
24450     (write-buffered *(ebp+0x10) ": stmt index: second argument '")
24451     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
24452     (write-buffered *(ebp+0x10) %eax)
24453     (write-buffered *(ebp+0x10) "' must be an int or offset\n")
24454     (flush *(ebp+0x10))
24455     (stop *(ebp+0x14) 1)
24456     # never gets here
24458 $check-mu-index-stmt:error-index-offset-atom-type:
24459     (write-buffered *(ebp+0x10) "fn ")
24460     8b/-> *(ebp+0xc) 0/r32/eax
24461     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24462     (write-buffered *(ebp+0x10) %eax)
24463     (write-buffered *(ebp+0x10) ": stmt index: offset '")
24464     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
24465     (write-buffered *(ebp+0x10) %eax)
24466     (write-buffered *(ebp+0x10) "' must specify the type of array elements\n")
24467     (flush *(ebp+0x10))
24468     (stop *(ebp+0x14) 1)
24469     # never gets here
24471 $check-mu-index-stmt:error-index-on-stack:
24472     (write-buffered *(ebp+0x10) "fn ")
24473     8b/-> *(ebp+0xc) 0/r32/eax
24474     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24475     (write-buffered *(ebp+0x10) %eax)
24476     (write-buffered *(ebp+0x10) ": stmt index: second argument '")
24477     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
24478     (write-buffered *(ebp+0x10) %eax)
24479     (write-buffered *(ebp+0x10) "' must be in a register\n")
24480     (flush *(ebp+0x10))
24481     (stop *(ebp+0x14) 1)
24482     # never gets here
24484 $check-mu-index-stmt:error-index-needs-offset:
24485     (write-buffered *(ebp+0x10) "fn ")
24486     8b/-> *(ebp+0xc) 0/r32/eax
24487     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24488     (write-buffered *(ebp+0x10) %eax)
24489     (write-buffered *(ebp+0x10) ": stmt index: cannot take an int for array '")
24490     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
24491     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
24492     (lookup *eax *(eax+4))  # Var-name Var-name => eax
24493     (write-buffered *(ebp+0x10) %eax)
24494     (write-buffered *(ebp+0x10) "'; create an offset instead. See mu.md for details.\n")
24495     (flush *(ebp+0x10))
24496     (stop *(ebp+0x14) 1)
24497     # never gets here
24499 $check-mu-index-stmt:error-too-many-inouts:
24500     (write-buffered *(ebp+0x10) "fn ")
24501     8b/-> *(ebp+0xc) 0/r32/eax
24502     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24503     (write-buffered *(ebp+0x10) %eax)
24504     (write-buffered *(ebp+0x10) ": stmt index: too many inouts (2 required)\n")
24505     (flush *(ebp+0x10))
24506     (stop *(ebp+0x14) 1)
24507     # never gets here
24509 $check-mu-index-stmt:error-too-few-outputs:
24510     (write-buffered *(ebp+0x10) "fn ")
24511     8b/-> *(ebp+0xc) 0/r32/eax
24512     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24513     (write-buffered *(ebp+0x10) %eax)
24514     (write-buffered *(ebp+0x10) ": stmt index: must have an output\n")
24515     (flush *(ebp+0x10))
24516     (stop *(ebp+0x14) 1)
24517     # never gets here
24519 $check-mu-index-stmt:error-too-many-outputs:
24520     (write-buffered *(ebp+0x10) "fn ")
24521     8b/-> *(ebp+0xc) 0/r32/eax
24522     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24523     (write-buffered *(ebp+0x10) %eax)
24524     (write-buffered *(ebp+0x10) ": stmt index: too many outputs (1 required)\n")
24525     (flush *(ebp+0x10))
24526     (stop *(ebp+0x14) 1)
24527     # never gets here
24529 $check-mu-index-stmt:error-output-not-in-register:
24530     (write-buffered *(ebp+0x10) "fn ")
24531     8b/-> *(ebp+0xc) 0/r32/eax
24532     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24533     (write-buffered *(ebp+0x10) %eax)
24534     (write-buffered *(ebp+0x10) ": stmt index: output '")
24535     (lookup *edi *(edi+4))  # Var-name Var-name => eax
24536     (write-buffered *(ebp+0x10) %eax)
24537     (write-buffered *(ebp+0x10) "' is not in a register\n")
24538     (flush *(ebp+0x10))
24539     (stop *(ebp+0x14) 1)
24540     # never gets here
24542 $check-mu-index-stmt:error-output-type-not-address:
24543     (write-buffered *(ebp+0x10) "fn ")
24544     8b/-> *(ebp+0xc) 0/r32/eax
24545     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24546     (write-buffered *(ebp+0x10) %eax)
24547     (write-buffered *(ebp+0x10) ": stmt index: output '")
24548     (lookup *edi *(edi+4))  # Var-name Var-name => eax
24549     (write-buffered *(ebp+0x10) %eax)
24550     (write-buffered *(ebp+0x10) "' must be an addr\n")
24551     (flush *(ebp+0x10))
24552     (stop *(ebp+0x14) 1)
24553     # never gets here
24555 $check-mu-index-stmt:error-bad-output-type:
24556     (write-buffered *(ebp+0x10) "fn ")
24557     8b/-> *(ebp+0xc) 0/r32/eax
24558     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24559     (write-buffered *(ebp+0x10) %eax)
24560     (write-buffered *(ebp+0x10) ": stmt index: output '")
24561     (lookup *edi *(edi+4))  # Var-name Var-name => eax
24562     (write-buffered *(ebp+0x10) %eax)
24563     (write-buffered *(ebp+0x10) "' does not have the right type\n")
24564     (flush *(ebp+0x10))
24565     (stop *(ebp+0x14) 1)
24566     # never gets here
24568 check-mu-length-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
24569     # . prologue
24570     55/push-ebp
24571     89/<- %ebp 4/r32/esp
24572     # . save registers
24573     50/push-eax
24574     51/push-ecx
24575     52/push-edx
24576     53/push-ebx
24577     56/push-esi
24578     57/push-edi
24579     # esi = stmt
24580     8b/-> *(ebp+8) 6/r32/esi
24581     # - check for 0 inouts
24582     # var base/ecx: (addr var) = stmt->inouts->value
24583     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
24584 $check-mu-length-stmt:check-no-inouts:
24585     3d/compare-eax-and 0/imm32
24586     0f 84/jump-if-= $check-mu-length-stmt:error-too-few-inouts/disp32
24587     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
24588     89/<- %ecx 0/r32/eax
24589     # - check base type is either (addr array ...) in register or (array ...) on stack
24590     # var base-type/ebx: (addr type-tree) = lookup(base->type)
24591     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
24592     89/<- %ebx 0/r32/eax
24593     # if base-type is an atom, abort with a precise error
24594     81 7/subop/compare *ebx 0/imm32/false  # Type-tree-is-atom
24595     {
24596       74/jump-if-= break/disp8
24597       (simple-mu-type? %ebx 3)  # array => eax
24598       3d/compare-eax-and 0/imm32/false
24599       0f 85/jump-if-!= $check-mu-length-stmt:error-base-array-atom-type/disp32
24600       0f 84/jump-if-= $check-mu-length-stmt:error-base-non-array-type/disp32
24601     }
24602 $check-mu-length-stmt:base-is-compound:
24603     # if type->left not addr or array, abort
24604     {
24605       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
24606       (simple-mu-type? %eax 2)  # addr => eax
24607       3d/compare-eax-and 0/imm32/false
24608       75/jump-if-!= break/disp8
24609       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
24610       (simple-mu-type? %eax 3)  # array => eax
24611       3d/compare-eax-and 0/imm32/false
24612       75/jump-if-!= break/disp8
24613       e9/jump $check-mu-length-stmt:error-base-non-array-type/disp32
24614     }
24615     # if (type->left == addr) ensure type->right->left == array and type->register exists
24616     {
24617       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
24618       (simple-mu-type? %eax 2)  # addr => eax
24619       3d/compare-eax-and 0/imm32/false
24620       74/jump-if-= break/disp8
24621 $check-mu-length-stmt:base-is-addr:
24622       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
24623       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
24624       (simple-mu-type? %eax 3)  # array => eax
24625       3d/compare-eax-and 0/imm32/false
24626       0f 84/jump-if-= $check-mu-length-stmt:error-base-non-array-type/disp32
24627 $check-mu-length-stmt:check-base-addr-is-register:
24628       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
24629       0f 84/jump-if-= $check-mu-length-stmt:error-base-address-array-type-on-stack/disp32
24630     }
24631     # if (type->left == array) ensure type->register doesn't exist
24632     {
24633       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
24634       (simple-mu-type? %eax 3)  # array => eax
24635       3d/compare-eax-and 0/imm32/false
24636       74/jump-if-= break/disp8
24637 $check-mu-length-stmt:base-is-array:
24638       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
24639       0f 85/jump-if-!= $check-mu-length-stmt:error-base-array-type-in-register/disp32
24640     }
24641     # if (base-type->left == addr) base-type = base-type->right
24642     {
24643       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
24644       (simple-mu-type? %eax 2)  # addr => eax
24645       3d/compare-eax-and 0/imm32/false
24646       74/jump-if-= break/disp8
24647       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
24648       89/<- %ebx 0/r32/eax
24649     }
24650     # - check for too many inouts
24651     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
24652     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
24653     3d/compare-eax-and 0/imm32/false
24654     0f 85/jump-if-!= $check-mu-length-stmt:error-too-many-inouts/disp32
24655     # - check for 0 outputs
24656     # var output/edi: (addr var) = stmt->outputs->value
24657     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
24658     3d/compare-eax-and 0/imm32/false
24659     0f 84/jump-if-= $check-mu-length-stmt:error-too-few-outputs/disp32
24660     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
24661     89/<- %edi 0/r32/eax
24662     # - check output type
24663     # must have a non-atomic type
24664     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
24665     (simple-mu-type? %eax 1)  # int => eax
24666     3d/compare-eax-and 0/imm32/false
24667     0f 84/jump-if-= $check-mu-length-stmt:error-invalid-output-type/disp32
24668     # - check for too many outputs
24669     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
24670     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
24671     3d/compare-eax-and 0/imm32/false
24672     0f 85/jump-if-!= $check-mu-length-stmt:error-too-many-outputs/disp32
24673 $check-mu-length-stmt:end:
24674     # . restore registers
24675     5f/pop-to-edi
24676     5e/pop-to-esi
24677     5b/pop-to-ebx
24678     5a/pop-to-edx
24679     59/pop-to-ecx
24680     58/pop-to-eax
24681     # . epilogue
24682     89/<- %esp 5/r32/ebp
24683     5d/pop-to-ebp
24684     c3/return
24686 $check-mu-length-stmt:error-base-non-array-type:
24687     (write-buffered *(ebp+0x10) "fn ")
24688     8b/-> *(ebp+0xc) 0/r32/eax
24689     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24690     (write-buffered *(ebp+0x10) %eax)
24691     (write-buffered *(ebp+0x10) ": stmt length: var '")
24692     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
24693     (write-buffered *(ebp+0x10) %eax)
24694     (write-buffered *(ebp+0x10) "' is not an array\n")
24695     (flush *(ebp+0x10))
24696     (stop *(ebp+0x14) 1)
24697     # never gets here
24699 $check-mu-length-stmt:error-base-array-atom-type:
24700     (write-buffered *(ebp+0x10) "fn ")
24701     8b/-> *(ebp+0xc) 0/r32/eax
24702     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24703     (write-buffered *(ebp+0x10) %eax)
24704     (write-buffered *(ebp+0x10) ": stmt length: array '")
24705     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
24706     (write-buffered *(ebp+0x10) %eax)
24707     (write-buffered *(ebp+0x10) "' must specify the type of its elements\n")
24708     (flush *(ebp+0x10))
24709     (stop *(ebp+0x14) 1)
24710     # never gets here
24712 $check-mu-length-stmt:error-base-address-array-type-on-stack:
24713     (write-buffered *(ebp+0x10) "fn ")
24714     8b/-> *(ebp+0xc) 0/r32/eax
24715     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24716     (write-buffered *(ebp+0x10) %eax)
24717     (write-buffered *(ebp+0x10) ": stmt length: var '")
24718     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
24719     (write-buffered *(ebp+0x10) %eax)
24720     (write-buffered *(ebp+0x10) "' is an addr to an array, and so must live in a register\n")
24721     (flush *(ebp+0x10))
24722     (stop *(ebp+0x14) 1)
24723     # never gets here
24725 $check-mu-length-stmt:error-base-array-type-in-register:
24726     (write-buffered *(ebp+0x10) "fn ")
24727     8b/-> *(ebp+0xc) 0/r32/eax
24728     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24729     (write-buffered *(ebp+0x10) %eax)
24730     (write-buffered *(ebp+0x10) ": stmt length: var '")
24731     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
24732     (write-buffered *(ebp+0x10) %eax)
24733     (write-buffered *(ebp+0x10) "' is an array, and so must live on the stack\n")
24734     (flush *(ebp+0x10))
24735     (stop *(ebp+0x14) 1)
24736     # never gets here
24738 $check-mu-length-stmt:error-too-few-inouts:
24739     (write-buffered *(ebp+0x10) "fn ")
24740     8b/-> *(ebp+0xc) 0/r32/eax
24741     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24742     (write-buffered *(ebp+0x10) %eax)
24743     (write-buffered *(ebp+0x10) ": stmt length: too few inouts (1 required)\n")
24744     (flush *(ebp+0x10))
24745     (stop *(ebp+0x14) 1)
24746     # never gets here
24748 $check-mu-length-stmt:error-invalid-index-type:
24749     (write-buffered *(ebp+0x10) "fn ")
24750     8b/-> *(ebp+0xc) 0/r32/eax
24751     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24752     (write-buffered *(ebp+0x10) %eax)
24753     (write-buffered *(ebp+0x10) ": stmt length: second argument '")
24754     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
24755     (write-buffered *(ebp+0x10) %eax)
24756     (write-buffered *(ebp+0x10) "' must be an int or offset\n")
24757     (flush *(ebp+0x10))
24758     (stop *(ebp+0x14) 1)
24759     # never gets here
24761 $check-mu-length-stmt:error-index-offset-atom-type:
24762     (write-buffered *(ebp+0x10) "fn ")
24763     8b/-> *(ebp+0xc) 0/r32/eax
24764     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24765     (write-buffered *(ebp+0x10) %eax)
24766     (write-buffered *(ebp+0x10) ": stmt length: offset '")
24767     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
24768     (write-buffered *(ebp+0x10) %eax)
24769     (write-buffered *(ebp+0x10) "' must specify the type of array elements\n")
24770     (flush *(ebp+0x10))
24771     (stop *(ebp+0x14) 1)
24772     # never gets here
24774 $check-mu-length-stmt:error-index-on-stack:
24775     (write-buffered *(ebp+0x10) "fn ")
24776     8b/-> *(ebp+0xc) 0/r32/eax
24777     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24778     (write-buffered *(ebp+0x10) %eax)
24779     (write-buffered *(ebp+0x10) ": stmt length: second argument '")
24780     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
24781     (write-buffered *(ebp+0x10) %eax)
24782     (write-buffered *(ebp+0x10) "' must be in a register\n")
24783     (flush *(ebp+0x10))
24784     (stop *(ebp+0x14) 1)
24785     # never gets here
24787 $check-mu-length-stmt:error-index-needs-offset:
24788     (write-buffered *(ebp+0x10) "fn ")
24789     8b/-> *(ebp+0xc) 0/r32/eax
24790     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24791     (write-buffered *(ebp+0x10) %eax)
24792     (write-buffered *(ebp+0x10) ": stmt length: cannot take an int for array '")
24793     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
24794     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
24795     (lookup *eax *(eax+4))  # Var-name Var-name => eax
24796     (write-buffered *(ebp+0x10) %eax)
24797     (write-buffered *(ebp+0x10) "'; create an offset instead. See mu.md for details.\n")
24798     (flush *(ebp+0x10))
24799     (stop *(ebp+0x14) 1)
24800     # never gets here
24802 $check-mu-length-stmt:error-too-many-inouts:
24803     (write-buffered *(ebp+0x10) "fn ")
24804     8b/-> *(ebp+0xc) 0/r32/eax
24805     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24806     (write-buffered *(ebp+0x10) %eax)
24807     (write-buffered *(ebp+0x10) ": stmt length: too many inouts (1 required)\n")
24808     (flush *(ebp+0x10))
24809     (stop *(ebp+0x14) 1)
24810     # never gets here
24812 $check-mu-length-stmt:error-too-few-outputs:
24813     (write-buffered *(ebp+0x10) "fn ")
24814     8b/-> *(ebp+0xc) 0/r32/eax
24815     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24816     (write-buffered *(ebp+0x10) %eax)
24817     (write-buffered *(ebp+0x10) ": stmt length: must have an output\n")
24818     (flush *(ebp+0x10))
24819     (stop *(ebp+0x14) 1)
24820     # never gets here
24822 $check-mu-length-stmt:error-too-many-outputs:
24823     (write-buffered *(ebp+0x10) "fn ")
24824     8b/-> *(ebp+0xc) 0/r32/eax
24825     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24826     (write-buffered *(ebp+0x10) %eax)
24827     (write-buffered *(ebp+0x10) ": stmt length: too many outputs (1 required)\n")
24828     (flush *(ebp+0x10))
24829     (stop *(ebp+0x14) 1)
24830     # never gets here
24832 $check-mu-length-stmt:error-output-not-in-register:
24833     (write-buffered *(ebp+0x10) "fn ")
24834     8b/-> *(ebp+0xc) 0/r32/eax
24835     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24836     (write-buffered *(ebp+0x10) %eax)
24837     (write-buffered *(ebp+0x10) ": stmt length: output '")
24838     (lookup *edi *(edi+4))  # Var-name Var-name => eax
24839     (write-buffered *(ebp+0x10) %eax)
24840     (write-buffered *(ebp+0x10) "' is not in a register\n")
24841     (flush *(ebp+0x10))
24842     (stop *(ebp+0x14) 1)
24843     # never gets here
24845 $check-mu-length-stmt:error-invalid-output-type:
24846     (write-buffered *(ebp+0x10) "fn ")
24847     8b/-> *(ebp+0xc) 0/r32/eax
24848     (lookup *eax *(eax+4))  # Function-name Function-name => eax
24849     (write-buffered *(ebp+0x10) %eax)
24850     (write-buffered *(ebp+0x10) ": stmt length: output '")
24851     (lookup *edi *(edi+4))  # Var-name Var-name => eax
24852     (write-buffered *(ebp+0x10) %eax)
24853     (write-buffered *(ebp+0x10) "' does not have the right type\n")
24854     (flush *(ebp+0x10))
24855     (stop *(ebp+0x14) 1)
24856     # never gets here
24858 check-mu-compute-offset-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
24859     # . prologue
24860     55/push-ebp
24861     89/<- %ebp 4/r32/esp
24862     # . save registers
24863     50/push-eax
24864     51/push-ecx
24865     52/push-edx
24866     53/push-ebx
24867     56/push-esi
24868     57/push-edi
24869     # esi = stmt
24870     8b/-> *(ebp+8) 6/r32/esi
24871     # - check for 0 inouts
24872     # var base/ecx: (addr var) = stmt->inouts->value
24873     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
24874 $check-mu-compute-offset-stmt:check-no-inouts:
24875     3d/compare-eax-and 0/imm32
24876     0f 84/jump-if-= $check-mu-compute-offset-stmt:error-too-few-inouts/disp32
24877     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
24878     89/<- %ecx 0/r32/eax
24879     # - check base type is either (addr array ...) in register or (array ...) on stack
24880     # var base-type/ebx: (addr type-tree) = lookup(base->type)
24881     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
24882     89/<- %ebx 0/r32/eax
24883     # if base-type is an atom, abort with a precise error
24884     81 7/subop/compare *ebx 0/imm32/false  # Type-tree-is-atom
24885     {
24886       74/jump-if-= break/disp8
24887       (simple-mu-type? %ebx 3)  # array => eax
24888       3d/compare-eax-and 0/imm32/false
24889       0f 85/jump-if-!= $check-mu-compute-offset-stmt:error-base-array-atom-type/disp32
24890       0f 84/jump-if-= $check-mu-compute-offset-stmt:error-base-non-array-type/disp32
24891     }
24892 $check-mu-compute-offset-stmt:base-is-compound:
24893     # if type->left not addr or array, abort
24894     {
24895       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
24896       (simple-mu-type? %eax 2)  # addr => eax
24897       3d/compare-eax-and 0/imm32/false
24898       75/jump-if-!= break/disp8
24899       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
24900       (simple-mu-type? %eax 3)  # array => eax
24901       3d/compare-eax-and 0/imm32/false
24902       75/jump-if-!= break/disp8
24903       e9/jump $check-mu-compute-offset-stmt:error-base-non-array-type/disp32
24904     }
24905     # if (type->left == addr) ensure type->right->left == array and type->register exists
24906     {
24907       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
24908       (simple-mu-type? %eax 2)  # addr => eax
24909       3d/compare-eax-and 0/imm32/false
24910       74/jump-if-= break/disp8
24911 $check-mu-compute-offset-stmt:base-is-addr:
24912       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
24913       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
24914       (simple-mu-type? %eax 3)  # array => eax
24915       3d/compare-eax-and 0/imm32/false
24916       0f 84/jump-if-= $check-mu-compute-offset-stmt:error-base-non-array-type/disp32
24917     }
24918     # if (base-type->left == addr) base-type = base-type->right
24919     {
24920       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
24921       (simple-mu-type? %eax 2)  # addr => eax
24922       3d/compare-eax-and 0/imm32/false
24923       74/jump-if-= break/disp8
24924       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
24925       89/<- %ebx 0/r32/eax
24926     }
24927     # - check for 1 inout
24928     # var index/ecx: (addr stmt-var) = stmt->inouts->next->value
24929     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
24930     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
24931 $check-mu-compute-offset-stmt:check-single-inout:
24932     3d/compare-eax-and 0/imm32
24933     0f 84/jump-if-= $check-mu-compute-offset-stmt:error-too-few-inouts/disp32
24934     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
24935     89/<- %ecx 0/r32/eax
24936     # - check index is either a literal or register
24937     # var index-type/edx: (addr type-tree)
24938     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
24939     89/<- %edx 0/r32/eax
24940     # index type must be a literal or int
24941     81 7/subop/compare *edx 0/imm32/false  # Type-tree-is-atom
24942     0f 84/jump-if-= $check-mu-compute-offset-stmt:error-invalid-index-type/disp32
24943     {
24944 $check-mu-compute-offset-stmt:index-type-is-atom:
24945       (simple-mu-type? %edx 0)  # literal => eax
24946       3d/compare-eax-and 0/imm32/false
24947       75/jump-if-!= break/disp8
24948       (simple-mu-type? %edx 1)  # int => eax
24949       3d/compare-eax-and 0/imm32/false
24950       75/jump-if-!= break/disp8
24951       e9/jump $check-mu-compute-offset-stmt:error-invalid-index-type/disp32
24952     }
24953     # - check for too many inouts
24954     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
24955     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
24956     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
24957     3d/compare-eax-and 0/imm32/false
24958     0f 85/jump-if-!= $check-mu-compute-offset-stmt:error-too-many-inouts/disp32
24959     # - check for 0 outputs
24960     # var output/edi: (addr var) = stmt->outputs->value
24961     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
24962     3d/compare-eax-and 0/imm32/false
24963     0f 84/jump-if-= $check-mu-compute-offset-stmt:error-too-few-outputs/disp32
24964     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
24965     89/<- %edi 0/r32/eax
24966     # - check output type
24967     # must have a non-atomic type
24968     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
24969     89/<- %edx 0/r32/eax
24970     81 7/subop/compare *edx 0/imm32/false  # Type-tree-is-atom
24971     0f 85/jump-if-!= $check-mu-compute-offset-stmt:error-output-type-not-offset/disp32
24972     # type must start with (offset ...)
24973     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
24974     (simple-mu-type? %eax 7)  # offset => eax
24975     3d/compare-eax-and 0/imm32/false
24976     0f 84/jump-if-= $check-mu-compute-offset-stmt:error-output-type-not-offset/disp32
24977     # if tail(base-type) != tail(output-type) abort
24978     (type-tail %ebx)  # => eax
24979     89/<- %ebx 0/r32/eax
24980     (type-tail %edx)  # => eax
24981     (type-equal? %ebx %eax)  # => eax
24982     3d/compare-eax-and 0/imm32/false
24983     0f 84/jump-if-= $check-mu-compute-offset-stmt:error-bad-output-type/disp32
24984     # - check for too many outputs
24985     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
24986     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
24987     3d/compare-eax-and 0/imm32/false
24988     0f 85/jump-if-!= $check-mu-compute-offset-stmt:error-too-many-outputs/disp32
24989 $check-mu-compute-offset-stmt:end:
24990     # . restore registers
24991     5f/pop-to-edi
24992     5e/pop-to-esi
24993     5b/pop-to-ebx
24994     5a/pop-to-edx
24995     59/pop-to-ecx
24996     58/pop-to-eax
24997     # . epilogue
24998     89/<- %esp 5/r32/ebp
24999     5d/pop-to-ebp
25000     c3/return
25002 $check-mu-compute-offset-stmt:error-base-non-array-type:
25003     (write-buffered *(ebp+0x10) "fn ")
25004     8b/-> *(ebp+0xc) 0/r32/eax
25005     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25006     (write-buffered *(ebp+0x10) %eax)
25007     (write-buffered *(ebp+0x10) ": stmt compute-offset: var '")
25008     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
25009     (write-buffered *(ebp+0x10) %eax)
25010     (write-buffered *(ebp+0x10) "' is not an array\n")
25011     (flush *(ebp+0x10))
25012     (stop *(ebp+0x14) 1)
25013     # never gets here
25015 $check-mu-compute-offset-stmt:error-base-array-atom-type:
25016     (write-buffered *(ebp+0x10) "fn ")
25017     8b/-> *(ebp+0xc) 0/r32/eax
25018     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25019     (write-buffered *(ebp+0x10) %eax)
25020     (write-buffered *(ebp+0x10) ": stmt compute-offset: array '")
25021     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
25022     (write-buffered *(ebp+0x10) %eax)
25023     (write-buffered *(ebp+0x10) "' must specify the type of its elements\n")
25024     (flush *(ebp+0x10))
25025     (stop *(ebp+0x14) 1)
25026     # never gets here
25028 $check-mu-compute-offset-stmt:error-too-few-inouts:
25029     (write-buffered *(ebp+0x10) "fn ")
25030     8b/-> *(ebp+0xc) 0/r32/eax
25031     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25032     (write-buffered *(ebp+0x10) %eax)
25033     (write-buffered *(ebp+0x10) ": stmt compute-offset: too few inouts (2 required)\n")
25034     (flush *(ebp+0x10))
25035     (stop *(ebp+0x14) 1)
25036     # never gets here
25038 $check-mu-compute-offset-stmt:error-invalid-index-type:
25039     (write-buffered *(ebp+0x10) "fn ")
25040     8b/-> *(ebp+0xc) 0/r32/eax
25041     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25042     (write-buffered *(ebp+0x10) %eax)
25043     (write-buffered *(ebp+0x10) ": stmt compute-offset: second argument '")
25044     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
25045     (write-buffered *(ebp+0x10) %eax)
25046     (write-buffered *(ebp+0x10) "' must be an int\n")
25047     (flush *(ebp+0x10))
25048     (stop *(ebp+0x14) 1)
25049     # never gets here
25051 $check-mu-compute-offset-stmt:error-index-offset-atom-type:
25052     (write-buffered *(ebp+0x10) "fn ")
25053     8b/-> *(ebp+0xc) 0/r32/eax
25054     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25055     (write-buffered *(ebp+0x10) %eax)
25056     (write-buffered *(ebp+0x10) ": stmt compute-offset: offset '")
25057     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
25058     (write-buffered *(ebp+0x10) %eax)
25059     (write-buffered *(ebp+0x10) "' must specify the type of array elements\n")
25060     (flush *(ebp+0x10))
25061     (stop *(ebp+0x14) 1)
25062     # never gets here
25064 $check-mu-compute-offset-stmt:error-index-on-stack:
25065     (write-buffered *(ebp+0x10) "fn ")
25066     8b/-> *(ebp+0xc) 0/r32/eax
25067     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25068     (write-buffered *(ebp+0x10) %eax)
25069     (write-buffered *(ebp+0x10) ": stmt compute-offset: second argument '")
25070     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
25071     (write-buffered *(ebp+0x10) %eax)
25072     (write-buffered *(ebp+0x10) "' must be in a register\n")
25073     (flush *(ebp+0x10))
25074     (stop *(ebp+0x14) 1)
25075     # never gets here
25077 $check-mu-compute-offset-stmt:error-too-many-inouts:
25078     (write-buffered *(ebp+0x10) "fn ")
25079     8b/-> *(ebp+0xc) 0/r32/eax
25080     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25081     (write-buffered *(ebp+0x10) %eax)
25082     (write-buffered *(ebp+0x10) ": stmt compute-offset: too many inouts (2 required)\n")
25083     (flush *(ebp+0x10))
25084     (stop *(ebp+0x14) 1)
25085     # never gets here
25087 $check-mu-compute-offset-stmt:error-too-few-outputs:
25088     (write-buffered *(ebp+0x10) "fn ")
25089     8b/-> *(ebp+0xc) 0/r32/eax
25090     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25091     (write-buffered *(ebp+0x10) %eax)
25092     (write-buffered *(ebp+0x10) ": stmt compute-offset: must have an output\n")
25093     (flush *(ebp+0x10))
25094     (stop *(ebp+0x14) 1)
25095     # never gets here
25097 $check-mu-compute-offset-stmt:error-too-many-outputs:
25098     (write-buffered *(ebp+0x10) "fn ")
25099     8b/-> *(ebp+0xc) 0/r32/eax
25100     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25101     (write-buffered *(ebp+0x10) %eax)
25102     (write-buffered *(ebp+0x10) ": stmt compute-offset: too many outputs (1 required)\n")
25103     (flush *(ebp+0x10))
25104     (stop *(ebp+0x14) 1)
25105     # never gets here
25107 $check-mu-compute-offset-stmt:error-output-not-in-register:
25108     (write-buffered *(ebp+0x10) "fn ")
25109     8b/-> *(ebp+0xc) 0/r32/eax
25110     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25111     (write-buffered *(ebp+0x10) %eax)
25112     (write-buffered *(ebp+0x10) ": stmt compute-offset: output '")
25113     (lookup *edi *(edi+4))  # Var-name Var-name => eax
25114     (write-buffered *(ebp+0x10) %eax)
25115     (write-buffered *(ebp+0x10) "' is not in a register\n")
25116     (flush *(ebp+0x10))
25117     (stop *(ebp+0x14) 1)
25118     # never gets here
25120 $check-mu-compute-offset-stmt:error-output-type-not-offset:
25121     (write-buffered *(ebp+0x10) "fn ")
25122     8b/-> *(ebp+0xc) 0/r32/eax
25123     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25124     (write-buffered *(ebp+0x10) %eax)
25125     (write-buffered *(ebp+0x10) ": stmt compute-offset: output '")
25126     (lookup *edi *(edi+4))  # Var-name Var-name => eax
25127     (write-buffered *(ebp+0x10) %eax)
25128     (write-buffered *(ebp+0x10) "' must be an offset\n")
25129     (flush *(ebp+0x10))
25130     (stop *(ebp+0x14) 1)
25131     # never gets here
25133 $check-mu-compute-offset-stmt:error-bad-output-type:
25134     (write-buffered *(ebp+0x10) "fn ")
25135     8b/-> *(ebp+0xc) 0/r32/eax
25136     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25137     (write-buffered *(ebp+0x10) %eax)
25138     (write-buffered *(ebp+0x10) ": stmt compute-offset: output '")
25139     (lookup *edi *(edi+4))  # Var-name Var-name => eax
25140     (write-buffered *(ebp+0x10) %eax)
25141     (write-buffered *(ebp+0x10) "' does not have the right type\n")
25142     (flush *(ebp+0x10))
25143     (stop *(ebp+0x14) 1)
25144     # never gets here
25146 check-mu-copy-object-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
25147     # . prologue
25148     55/push-ebp
25149     89/<- %ebp 4/r32/esp
25150     # . save registers
25151     50/push-eax
25152     51/push-ecx
25153     53/push-ebx
25154     56/push-esi
25155     57/push-edi
25156     # esi = stmt
25157     8b/-> *(ebp+8) 6/r32/esi
25158 $check-mu-copy-object-stmt:check-for-output:
25159     # if stmt->outputs abort
25160     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
25161     3d/compare-eax-and 0/imm32
25162     0f 85/jump-if-!= $check-mu-copy-object-stmt:error-too-many-outputs/disp32
25163 $check-mu-copy-object-stmt:get-left:
25164     # var dest/edi: (addr stmt-var) = stmt->inouts
25165     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
25166     89/<- %edi 0/r32/eax
25167     # zero inouts
25168     3d/compare-eax-and 0/imm32
25169     0f 84/jump-if-= $check-mu-copy-object-stmt:error-incorrect-inouts/disp32
25170 $check-mu-copy-object-stmt:get-src:
25171     # var src/esi: (addr stmt-var) = dest->next
25172     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
25173     89/<- %esi 0/r32/eax
25174     # 1 inout
25175     3d/compare-eax-and 0/imm32
25176     0f 84/jump-if-= $check-mu-copy-object-stmt:error-incorrect-inouts/disp32
25177     # > 2 inouts
25178     (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
25179     3d/compare-eax-and 0/imm32
25180     0f 85/jump-if-!= $check-mu-copy-object-stmt:error-incorrect-inouts/disp32
25181 $check-mu-copy-object-stmt:types:
25182     # var src-type/ecx: (addr type-tree) = src->value->type
25183     (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
25184     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
25185     89/<- %ecx 0/r32/eax
25186     # if (src->is-deref?) src-type = src-type->payload
25187     8b/-> *(esi+0x10) 0/r32/eax  # Stmt-var-is-deref
25188     3d/compare-eax-and 0/imm32/false
25189     {
25190       74/jump-if-= break/disp8
25191       (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
25192       # if src-type->right is null, src-type = src-type->left
25193       81 7/subop/compare *(eax+0xc) 0/imm32  # Type-tree-right
25194       {
25195         75/jump-if-!= break/disp8
25196         (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
25197       }
25198       89/<- %ecx 0/r32/eax
25199     }
25200     # if src-type is not addr, abort
25201     (mu-addr-type? %ecx)  # => eax
25202     3d/compare-eax-and 0/imm32/false
25203     0f 84/jump-if-= $check-mu-copy-object-stmt:error-invalid-types/disp32
25204     # var dest-type/ebx: (addr type-tree) = dest->value->type
25205     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
25206     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
25207     89/<- %ebx 0/r32/eax
25208     # if (dest->is-deref?) dest-type = dest-type->payload
25209     8b/-> *(edi+0x10) 0/r32/eax  # Stmt-var-is-deref
25210     3d/compare-eax-and 0/imm32/false
25211     {
25212       74/jump-if-= break/disp8
25213       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
25214       # if dest-type->right is null, dest-type = dest-type->left
25215       81 7/subop/compare *(eax+0xc) 0/imm32  # Type-tree-right
25216       {
25217         75/jump-if-!= break/disp8
25218         (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
25219       }
25220       89/<- %ebx 0/r32/eax
25221     }
25222     # if (dest-type != src-type) abort
25223     (type-equal? %ecx %ebx)  # => eax
25224     3d/compare-eax-and 0/imm32
25225     0f 84/jump-if-= $check-mu-copy-object-stmt:error-invalid-types/disp32
25226 $check-mu-copy-object-stmt:end:
25227     # . restore registers
25228     5f/pop-to-edi
25229     5e/pop-to-esi
25230     5b/pop-to-ebx
25231     59/pop-to-ecx
25232     58/pop-to-eax
25233     # . epilogue
25234     89/<- %esp 5/r32/ebp
25235     5d/pop-to-ebp
25236     c3/return
25238 $check-mu-copy-object-stmt:error-incorrect-inouts:
25239     (write-buffered *(ebp+0x10) "fn ")
25240     8b/-> *(ebp+0xc) 0/r32/eax
25241     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25242     (write-buffered *(ebp+0x10) %eax)
25243     (write-buffered *(ebp+0x10) ": stmt 'copy-object' must have two inouts\n")
25244     (flush *(ebp+0x10))
25245     (stop *(ebp+0x14) 1)
25246     # never gets here
25248 $check-mu-copy-object-stmt:error-too-many-outputs:
25249     (write-buffered *(ebp+0x10) "fn ")
25250     8b/-> *(ebp+0xc) 0/r32/eax
25251     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25252     (write-buffered *(ebp+0x10) %eax)
25253     (write-buffered *(ebp+0x10) ": stmt 'copy-object' must not have any outputs\n")
25254     (flush *(ebp+0x10))
25255     (stop *(ebp+0x14) 1)
25256     # never gets here
25258 $check-mu-copy-object-stmt:error-invalid-types:
25259     (write-buffered *(ebp+0x10) "fn ")
25260     8b/-> *(ebp+0xc) 0/r32/eax
25261     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25262     (write-buffered *(ebp+0x10) %eax)
25263     (write-buffered *(ebp+0x10) ": stmt copy-object: two inouts with identical addr types expected\n")
25264     (flush *(ebp+0x10))
25265     (stop *(ebp+0x14) 1)
25266     # never gets here
25268 check-mu-clear-object-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
25269     # . prologue
25270     55/push-ebp
25271     89/<- %ebp 4/r32/esp
25272     # . save registers
25273     50/push-eax
25274     51/push-ecx
25275     53/push-ebx
25276     56/push-esi
25277     57/push-edi
25278     # esi = stmt
25279     8b/-> *(ebp+8) 6/r32/esi
25280 $check-mu-clear-object-stmt:check-for-output:
25281     # if stmt->outputs abort
25282     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
25283     3d/compare-eax-and 0/imm32
25284     0f 85/jump-if-!= $check-mu-clear-object-stmt:error-too-many-outputs/disp32
25285 $check-mu-clear-object-stmt:get-left:
25286     # var dest/edi: (addr stmt-var) = stmt->inouts
25287     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
25288     89/<- %edi 0/r32/eax
25289     # zero inouts
25290     3d/compare-eax-and 0/imm32
25291     0f 84/jump-if-= $check-mu-clear-object-stmt:error-incorrect-inouts/disp32
25292 $check-mu-clear-object-stmt:get-src:
25293     # > 1 inout
25294     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
25295     3d/compare-eax-and 0/imm32
25296     0f 85/jump-if-!= $check-mu-clear-object-stmt:error-incorrect-inouts/disp32
25297 $check-mu-clear-object-stmt:types:
25298     # var src-type/ecx: (addr type-tree) = src->value->type
25299     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
25300     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
25301     89/<- %ecx 0/r32/eax
25302     # if (src->is-deref?) src-type = src-type->payload
25303     8b/-> *(edi+0x10) 0/r32/eax  # Stmt-var-is-deref
25304     3d/compare-eax-and 0/imm32/false
25305     {
25306       74/jump-if-= break/disp8
25307       (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
25308       # if src-type->right is null, src-type = src-type->left
25309       81 7/subop/compare *(eax+0xc) 0/imm32  # Type-tree-right
25310       {
25311         75/jump-if-!= break/disp8
25312         (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
25313       }
25314       89/<- %ecx 0/r32/eax
25315     }
25316     # if src-type is not addr, abort
25317     (mu-addr-type? %ecx)  # => eax
25318     3d/compare-eax-and 0/imm32/false
25319     0f 84/jump-if-= $check-mu-clear-object-stmt:error-invalid-type/disp32
25320 $check-mu-clear-object-stmt:end:
25321     # . restore registers
25322     5f/pop-to-edi
25323     5e/pop-to-esi
25324     5b/pop-to-ebx
25325     59/pop-to-ecx
25326     58/pop-to-eax
25327     # . epilogue
25328     89/<- %esp 5/r32/ebp
25329     5d/pop-to-ebp
25330     c3/return
25332 $check-mu-clear-object-stmt:error-incorrect-inouts:
25333     (write-buffered *(ebp+0x10) "fn ")
25334     8b/-> *(ebp+0xc) 0/r32/eax
25335     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25336     (write-buffered *(ebp+0x10) %eax)
25337     (write-buffered *(ebp+0x10) ": stmt 'clear-object' must have a single inout\n")
25338     (flush *(ebp+0x10))
25339     (stop *(ebp+0x14) 1)
25340     # never gets here
25342 $check-mu-clear-object-stmt:error-too-many-outputs:
25343     (write-buffered *(ebp+0x10) "fn ")
25344     8b/-> *(ebp+0xc) 0/r32/eax
25345     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25346     (write-buffered *(ebp+0x10) %eax)
25347     (write-buffered *(ebp+0x10) ": stmt 'clear-object' must not have any outputs\n")
25348     (flush *(ebp+0x10))
25349     (stop *(ebp+0x14) 1)
25350     # never gets here
25352 $check-mu-clear-object-stmt:error-invalid-type:
25353     (write-buffered *(ebp+0x10) "fn ")
25354     8b/-> *(ebp+0xc) 0/r32/eax
25355     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25356     (write-buffered *(ebp+0x10) %eax)
25357     (write-buffered *(ebp+0x10) ": stmt clear-object: inout must have an addr type\n")
25358     (flush *(ebp+0x10))
25359     (stop *(ebp+0x14) 1)
25360     # never gets here
25362 check-mu-allocate-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
25363     # . prologue
25364     55/push-ebp
25365     89/<- %ebp 4/r32/esp
25366     # . save registers
25367     50/push-eax
25368     53/push-ebx
25369     56/push-esi
25370     57/push-edi
25371     # esi = stmt
25372     8b/-> *(ebp+8) 6/r32/esi
25373 $check-mu-allocate-stmt:check-for-output:
25374     # if stmt->outputs abort
25375     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
25376     3d/compare-eax-and 0/imm32
25377     0f 85/jump-if-!= $check-mu-allocate-stmt:error-too-many-outputs/disp32
25378 $check-mu-allocate-stmt:get-target:
25379     # var target/edi: (addr stmt-var) = stmt->inouts
25380     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
25381     89/<- %edi 0/r32/eax
25382     # zero inouts
25383     3d/compare-eax-and 0/imm32
25384     0f 84/jump-if-= $check-mu-allocate-stmt:error-incorrect-inouts/disp32
25385     # > 1 inouts
25386     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
25387     3d/compare-eax-and 0/imm32
25388     0f 85/jump-if-!= $check-mu-allocate-stmt:error-incorrect-inouts/disp32
25389 $check-mu-allocate-stmt:check-type:
25390     # var target-type/ebx: (addr type-tree) = target->value->type
25391     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
25392     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
25393     89/<- %ebx 0/r32/eax
25394     # if (target->is-deref?) target-type = target-type->payload
25395     8b/-> *(edi+0x10) 0/r32/eax  # Stmt-var-is-deref
25396     3d/compare-eax-and 0/imm32/false
25397     {
25398       74/jump-if-= break/disp8
25399       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
25400       # if target-type->right is null, target-type = target-type->left
25401       81 7/subop/compare *(eax+0xc) 0/imm32  # Type-tree-right
25402       {
25403         75/jump-if-!= break/disp8
25404         (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
25405       }
25406       89/<- %ebx 0/r32/eax
25407     }
25408     # if target-type is not addr, abort
25409     (mu-addr-type? %ebx)  # => eax
25410     3d/compare-eax-and 0/imm32/false
25411     0f 84/jump-if-= $check-mu-allocate-stmt:error-invalid-type/disp32
25412     # if target-type->right is an atom, abort
25413     (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
25414     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
25415     0f 85/jump-if-!= $check-mu-allocate-stmt:error-invalid-type/disp32
25416     # if target-type->right->left is not handle, abort
25417     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
25418     (simple-mu-type? %eax 4)  # handle => eax
25419     3d/compare-eax-and 0/imm32/false
25420     0f 84/jump-if-= $check-mu-allocate-stmt:error-invalid-type/disp32
25421 $check-mu-allocate-stmt:end:
25422     # . restore registers
25423     5f/pop-to-edi
25424     5e/pop-to-esi
25425     5b/pop-to-ebx
25426     58/pop-to-eax
25427     # . epilogue
25428     89/<- %esp 5/r32/ebp
25429     5d/pop-to-ebp
25430     c3/return
25432 $check-mu-allocate-stmt:error-incorrect-inouts:
25433     (write-buffered *(ebp+0x10) "fn ")
25434     8b/-> *(ebp+0xc) 0/r32/eax
25435     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25436     (write-buffered *(ebp+0x10) %eax)
25437     (write-buffered *(ebp+0x10) ": stmt 'allocate' must have a single inout\n")
25438     (flush *(ebp+0x10))
25439     (stop *(ebp+0x14) 1)
25440     # never gets here
25442 $check-mu-allocate-stmt:error-too-many-outputs:
25443     (write-buffered *(ebp+0x10) "fn ")
25444     8b/-> *(ebp+0xc) 0/r32/eax
25445     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25446     (write-buffered *(ebp+0x10) %eax)
25447     (write-buffered *(ebp+0x10) ": stmt 'allocate' must not have any outputs\n")
25448     (flush *(ebp+0x10))
25449     (stop *(ebp+0x14) 1)
25450     # never gets here
25452 $check-mu-allocate-stmt:error-invalid-type:
25453     (write-buffered *(ebp+0x10) "fn ")
25454     8b/-> *(ebp+0xc) 0/r32/eax
25455     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25456     (write-buffered *(ebp+0x10) %eax)
25457     (write-buffered *(ebp+0x10) ": stmt allocate: inout '")
25458     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
25459     (lookup *eax *(eax+4))  # Var-name Var-name => eax
25460     (write-buffered *(ebp+0x10) %eax)
25461     (write-buffered *(ebp+0x10) "' must have type (addr handle ...)\n")
25462     (flush *(ebp+0x10))
25463     (stop *(ebp+0x14) 1)
25464     # never gets here
25466 check-mu-populate-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
25467     # . prologue
25468     55/push-ebp
25469     89/<- %ebp 4/r32/esp
25470     # . save registers
25471     50/push-eax
25472     53/push-ebx
25473     56/push-esi
25474     57/push-edi
25475     # esi = stmt
25476     8b/-> *(ebp+8) 6/r32/esi
25477 $check-mu-populate-stmt:check-for-output:
25478     # if stmt->outputs abort
25479     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
25480     3d/compare-eax-and 0/imm32
25481     0f 85/jump-if-!= $check-mu-populate-stmt:error-too-many-outputs/disp32
25482 $check-mu-populate-stmt:get-target:
25483     # var target/edi: (addr stmt-var) = stmt->inouts
25484     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
25485     89/<- %edi 0/r32/eax
25486     # zero inouts
25487     3d/compare-eax-and 0/imm32
25488     0f 84/jump-if-= $check-mu-populate-stmt:error-incorrect-inouts/disp32
25489 $check-mu-populate-stmt:get-length:
25490     # var length/esi: (addr stmt-var) = dest->next
25491     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
25492     89/<- %esi 0/r32/eax
25493     # 1 inout
25494     3d/compare-eax-and 0/imm32
25495     0f 84/jump-if-= $check-mu-populate-stmt:error-incorrect-inouts/disp32
25496     # > 2 inouts
25497     (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
25498     3d/compare-eax-and 0/imm32
25499     0f 85/jump-if-!= $check-mu-populate-stmt:error-incorrect-inouts/disp32
25500 $check-mu-populate-stmt:check-target-type:
25501     # var target-type/ebx: (addr type-tree) = target->value->type
25502     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
25503     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
25504     89/<- %ebx 0/r32/eax
25505 $check-mu-populate-stmt:check-target-type-deref:
25506     # if (target->is-deref?) target-type = target-type->payload
25507     8b/-> *(edi+0x10) 0/r32/eax  # Stmt-var-is-deref
25508     3d/compare-eax-and 0/imm32/false
25509     {
25510       74/jump-if-= break/disp8
25511       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
25512       # if target-type->right is null, target-type = target-type->left
25513       81 7/subop/compare *(eax+0xc) 0/imm32  # Type-tree-right
25514       {
25515         75/jump-if-!= break/disp8
25516         (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
25517       }
25518       89/<- %ebx 0/r32/eax
25519     }
25520 $check-mu-populate-stmt:check-target-type-addr:
25521     # if target-type is not addr, abort
25522     (mu-addr-type? %ebx)  # => eax
25523     3d/compare-eax-and 0/imm32/false
25524     0f 84/jump-if-= $check-mu-populate-stmt:error-invalid-target-type/disp32
25525     # if target-type->right is an atom, abort
25526     (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
25527     89/<- %ebx 0/r32/eax
25528     81 7/subop/compare *ebx 0/imm32/false  # Type-tree-is-atom
25529     0f 85/jump-if-!= $check-mu-populate-stmt:error-invalid-target-type/disp32
25530 $check-mu-populate-stmt:check-target-type-handle:
25531     # if target-type->right->left is not handle, abort
25532     (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
25533     (simple-mu-type? %eax 4)  # handle => eax
25534     3d/compare-eax-and 0/imm32/false
25535     0f 84/jump-if-= $check-mu-populate-stmt:error-invalid-target-type/disp32
25536     # if target-type->right->right is an atom, abort
25537     (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
25538     89/<- %ebx 0/r32/eax
25539     81 7/subop/compare *ebx 0/imm32/false  # Type-tree-is-atom
25540     0f 85/jump-if-!= $check-mu-populate-stmt:error-invalid-target-type/disp32
25541 $check-mu-populate-stmt:check-target-type-array:
25542     # if target-type->right->right->left is not array, abort
25543     (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
25544     (simple-mu-type? %eax 3)  # array => eax
25545     3d/compare-eax-and 0/imm32/false
25546     0f 84/jump-if-= $check-mu-populate-stmt:error-invalid-target-type/disp32
25547 $check-mu-populate-stmt:check-length-type:
25548     (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
25549     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
25550     89/<- %ebx 0/r32/eax
25551     (simple-mu-type? %ebx 0)  # literal => eax
25552     3d/compare-eax-and 0/imm32/false
25553     75/jump-if-!= $check-mu-populate-stmt:end/disp8
25554     (simple-mu-type? %ebx 1)  # int => eax
25555     3d/compare-eax-and 0/imm32/false
25556     0f 84/jump-if-= $check-mu-populate-stmt:error-invalid-length-type/disp32
25557 $check-mu-populate-stmt:end:
25558     # . restore registers
25559     5f/pop-to-edi
25560     5e/pop-to-esi
25561     5b/pop-to-ebx
25562     58/pop-to-eax
25563     # . epilogue
25564     89/<- %esp 5/r32/ebp
25565     5d/pop-to-ebp
25566     c3/return
25568 $check-mu-populate-stmt:error-incorrect-inouts:
25569     (write-buffered *(ebp+0x10) "fn ")
25570     8b/-> *(ebp+0xc) 0/r32/eax
25571     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25572     (write-buffered *(ebp+0x10) %eax)
25573     (write-buffered *(ebp+0x10) ": stmt 'populate' must have two inouts\n")
25574     (flush *(ebp+0x10))
25575     (stop *(ebp+0x14) 1)
25576     # never gets here
25578 $check-mu-populate-stmt:error-too-many-outputs:
25579     (write-buffered *(ebp+0x10) "fn ")
25580     8b/-> *(ebp+0xc) 0/r32/eax
25581     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25582     (write-buffered *(ebp+0x10) %eax)
25583     (write-buffered *(ebp+0x10) ": stmt 'populate' must not have any outputs\n")
25584     (flush *(ebp+0x10))
25585     (stop *(ebp+0x14) 1)
25586     # never gets here
25588 $check-mu-populate-stmt:error-invalid-target-type:
25589     (write-buffered *(ebp+0x10) "fn ")
25590     8b/-> *(ebp+0xc) 0/r32/eax
25591     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25592     (write-buffered *(ebp+0x10) %eax)
25593     (write-buffered *(ebp+0x10) ": stmt populate: first inout '")
25594     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
25595     (lookup *eax *(eax+4))  # Var-name Var-name => eax
25596     (write-buffered *(ebp+0x10) %eax)
25597     (write-buffered *(ebp+0x10) "' must have type (addr handle array ...)\n")
25598     (flush *(ebp+0x10))
25599     (stop *(ebp+0x14) 1)
25600     # never gets here
25602 $check-mu-populate-stmt:error-invalid-length-type:
25603     (write-buffered *(ebp+0x10) "fn ")
25604     8b/-> *(ebp+0xc) 0/r32/eax
25605     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25606     (write-buffered *(ebp+0x10) %eax)
25607     (write-buffered *(ebp+0x10) ": stmt populate: second inout '")
25608     (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
25609     (lookup *eax *(eax+4))  # Var-name Var-name => eax
25610     (write-buffered *(ebp+0x10) %eax)
25611     (write-buffered *(ebp+0x10) "' must be an int\n")
25612     (flush *(ebp+0x10))
25613     (stop *(ebp+0x14) 1)
25614     # never gets here
25616 check-mu-populate-stream-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
25617     # . prologue
25618     55/push-ebp
25619     89/<- %ebp 4/r32/esp
25620     # . save registers
25621     50/push-eax
25622     53/push-ebx
25623     56/push-esi
25624     57/push-edi
25625     # esi = stmt
25626     8b/-> *(ebp+8) 6/r32/esi
25627 $check-mu-populate-stream-stmt:check-for-output:
25628     # if stmt->outputs abort
25629     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
25630     3d/compare-eax-and 0/imm32
25631     0f 85/jump-if-!= $check-mu-populate-stream-stmt:error-too-many-outputs/disp32
25632 $check-mu-populate-stream-stmt:get-target:
25633     # var target/edi: (addr stmt-var) = stmt->inouts
25634     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
25635     89/<- %edi 0/r32/eax
25636     # zero inouts
25637     3d/compare-eax-and 0/imm32
25638     0f 84/jump-if-= $check-mu-populate-stream-stmt:error-incorrect-inouts/disp32
25639 $check-mu-populate-stream-stmt:get-length:
25640     # var length/esi: (addr stmt-var) = dest->next
25641     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
25642     89/<- %esi 0/r32/eax
25643     # 1 inout
25644     3d/compare-eax-and 0/imm32
25645     0f 84/jump-if-= $check-mu-populate-stream-stmt:error-incorrect-inouts/disp32
25646     # > 2 inouts
25647     (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
25648     3d/compare-eax-and 0/imm32
25649     0f 85/jump-if-!= $check-mu-populate-stream-stmt:error-incorrect-inouts/disp32
25650 $check-mu-populate-stream-stmt:check-target-type:
25651     # var target-type/ebx: (addr type-tree) = target->value->type
25652     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
25653     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
25654     89/<- %ebx 0/r32/eax
25655 $check-mu-populate-stream-stmt:check-target-type-deref:
25656     # if (target->is-deref?) target-type = target-type->payload
25657     8b/-> *(edi+0x10) 0/r32/eax  # Stmt-var-is-deref
25658     3d/compare-eax-and 0/imm32/false
25659     {
25660       74/jump-if-= break/disp8
25661       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
25662       # if target-type->right is null, target-type = target-type->left
25663       81 7/subop/compare *(eax+0xc) 0/imm32  # Type-tree-right
25664       {
25665         75/jump-if-!= break/disp8
25666         (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
25667       }
25668       89/<- %ebx 0/r32/eax
25669     }
25670 $check-mu-populate-stream-stmt:check-target-type-addr:
25671     # if target-type is not addr, abort
25672     (mu-addr-type? %ebx)  # => eax
25673     3d/compare-eax-and 0/imm32/false
25674     0f 84/jump-if-= $check-mu-populate-stream-stmt:error-invalid-target-type/disp32
25675     # if target-type->right is an atom, abort
25676     (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
25677     89/<- %ebx 0/r32/eax
25678     81 7/subop/compare *ebx 0/imm32/false  # Type-tree-is-atom
25679     0f 85/jump-if-!= $check-mu-populate-stream-stmt:error-invalid-target-type/disp32
25680 $check-mu-populate-stream-stmt:check-target-type-handle:
25681     # if target-type->right->left is not handle, abort
25682     (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
25683     (simple-mu-type? %eax 4)  # handle => eax
25684     3d/compare-eax-and 0/imm32/false
25685     0f 84/jump-if-= $check-mu-populate-stream-stmt:error-invalid-target-type/disp32
25686     # if target-type->right->right is an atom, abort
25687     (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
25688     89/<- %ebx 0/r32/eax
25689     81 7/subop/compare *ebx 0/imm32/false  # Type-tree-is-atom
25690     0f 85/jump-if-!= $check-mu-populate-stream-stmt:error-invalid-target-type/disp32
25691 $check-mu-populate-stream-stmt:check-target-type-stream:
25692     # if target-type->right->right->left is not stream, abort
25693     (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
25694     (simple-mu-type? %eax 0xb)  # stream => eax
25695     3d/compare-eax-and 0/imm32/false
25696     0f 84/jump-if-= $check-mu-populate-stream-stmt:error-invalid-target-type/disp32
25697 $check-mu-populate-stream-stmt:check-length-type:
25698     (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
25699     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
25700     89/<- %ebx 0/r32/eax
25701     (simple-mu-type? %ebx 0)  # literal => eax
25702     3d/compare-eax-and 0/imm32/false
25703     75/jump-if-!= $check-mu-populate-stream-stmt:end/disp8
25704     (simple-mu-type? %ebx 1)  # int => eax
25705     3d/compare-eax-and 0/imm32/false
25706     0f 84/jump-if-= $check-mu-populate-stream-stmt:error-invalid-length-type/disp32
25707 $check-mu-populate-stream-stmt:end:
25708     # . restore registers
25709     5f/pop-to-edi
25710     5e/pop-to-esi
25711     5b/pop-to-ebx
25712     58/pop-to-eax
25713     # . epilogue
25714     89/<- %esp 5/r32/ebp
25715     5d/pop-to-ebp
25716     c3/return
25718 $check-mu-populate-stream-stmt:error-incorrect-inouts:
25719     (write-buffered *(ebp+0x10) "fn ")
25720     8b/-> *(ebp+0xc) 0/r32/eax
25721     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25722     (write-buffered *(ebp+0x10) %eax)
25723     (write-buffered *(ebp+0x10) ": stmt 'populate-stream' must have two inouts\n")
25724     (flush *(ebp+0x10))
25725     (stop *(ebp+0x14) 1)
25726     # never gets here
25728 $check-mu-populate-stream-stmt:error-too-many-outputs:
25729     (write-buffered *(ebp+0x10) "fn ")
25730     8b/-> *(ebp+0xc) 0/r32/eax
25731     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25732     (write-buffered *(ebp+0x10) %eax)
25733     (write-buffered *(ebp+0x10) ": stmt 'populate-stream' must not have any outputs\n")
25734     (flush *(ebp+0x10))
25735     (stop *(ebp+0x14) 1)
25736     # never gets here
25738 $check-mu-populate-stream-stmt:error-invalid-target-type:
25739     (write-buffered *(ebp+0x10) "fn ")
25740     8b/-> *(ebp+0xc) 0/r32/eax
25741     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25742     (write-buffered *(ebp+0x10) %eax)
25743     (write-buffered *(ebp+0x10) ": stmt populate-stream: first inout '")
25744     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
25745     (lookup *eax *(eax+4))  # Var-name Var-name => eax
25746     (write-buffered *(ebp+0x10) %eax)
25747     (write-buffered *(ebp+0x10) "' must have type (addr handle stream ...)\n")
25748     (flush *(ebp+0x10))
25749     (stop *(ebp+0x14) 1)
25750     # never gets here
25752 $check-mu-populate-stream-stmt:error-invalid-length-type:
25753     (write-buffered *(ebp+0x10) "fn ")
25754     8b/-> *(ebp+0xc) 0/r32/eax
25755     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25756     (write-buffered *(ebp+0x10) %eax)
25757     (write-buffered *(ebp+0x10) ": stmt populate-stream: second inout '")
25758     (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
25759     (lookup *eax *(eax+4))  # Var-name Var-name => eax
25760     (write-buffered *(ebp+0x10) %eax)
25761     (write-buffered *(ebp+0x10) "' must be an int\n")
25762     (flush *(ebp+0x10))
25763     (stop *(ebp+0x14) 1)
25764     # never gets here
25766 check-mu-read-from-stream-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
25767     # . prologue
25768     55/push-ebp
25769     89/<- %ebp 4/r32/esp
25770     # . save registers
25771     50/push-eax
25772     51/push-ecx
25773     52/push-edx
25774     53/push-ebx
25775     56/push-esi
25776     57/push-edi
25777     # esi = stmt
25778     8b/-> *(ebp+8) 6/r32/esi
25779     # - check for 0 inouts
25780     # var base/ecx: (addr var) = stmt->inouts->value
25781     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
25782 $check-mu-read-from-stream-stmt:check-no-inouts:
25783     3d/compare-eax-and 0/imm32
25784     0f 84/jump-if-= $check-mu-read-from-stream-stmt:error-too-few-inouts/disp32
25785     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
25786     89/<- %ecx 0/r32/eax
25787     # - check base type is (addr stream T)
25788     # var base-type/ebx: (addr type-tree) = lookup(base->type)
25789     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
25790     89/<- %ebx 0/r32/eax
25791 $check-mu-read-from-stream-stmt:check-base-is-compound:
25792     # if base-type is an atom, abort
25793     81 7/subop/compare *ebx 0/imm32/false  # Type-tree-is-atom
25794     0f 85/jump-if-!= $check-mu-read-from-stream-stmt:error-invalid-base-type/disp32
25795 $check-mu-read-from-stream-stmt:check-base-is-addr:
25796     # if type->left not addr, abort
25797     (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
25798     (simple-mu-type? %eax 2)  # addr => eax
25799     3d/compare-eax-and 0/imm32/false
25800     0f 84/jump-if-= $check-mu-read-from-stream-stmt:error-invalid-base-type/disp32
25801 $check-mu-read-from-stream-stmt:check-base-is-addr-to-stream:
25802     # base-type = base-type->right
25803     (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
25804     89/<- %ebx 0/r32/eax
25805     # ensure base-type->left == stream
25806     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
25807     (simple-mu-type? %eax 0xb)  # stream => eax
25808     3d/compare-eax-and 0/imm32/false
25809     0f 84/jump-if-= $check-mu-read-from-stream-stmt:error-invalid-base-type/disp32
25810     # - check target type is (addr T)
25811     # var target/ecx: (addr stmt-var) = stmt->inouts->next->value
25812     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
25813     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
25814 $check-mu-read-from-stream-stmt:check-single-inout:
25815     3d/compare-eax-and 0/imm32
25816     0f 84/jump-if-= $check-mu-read-from-stream-stmt:error-too-few-inouts/disp32
25817     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
25818     89/<- %ecx 0/r32/eax
25819     # var target-type/edx: (addr type-tree)
25820     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
25821     89/<- %edx 0/r32/eax
25822     # if target-type is an atom, it must be a literal or int
25823 $check-mu-read-from-stream-stmt:check-target-is-compound:
25824     81 7/subop/compare *edx 0/imm32/false  # Type-tree-is-atom
25825     0f 85/jump-if-!= $check-mu-read-from-stream-stmt:error-target-type-not-address/disp32
25826 $check-mu-read-from-stream-stmt:check-target-type:
25827     # target type must start with (addr ...)
25828     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
25829     (simple-mu-type? %eax 2)  # addr => eax
25830     3d/compare-eax-and 0/imm32/false
25831     0f 84/jump-if-= $check-mu-read-from-stream-stmt:error-target-type-not-address/disp32
25832     # if tail(base-type) != tail(target-type) abort
25833     (type-tail %ebx)  # => eax
25834     89/<- %ebx 0/r32/eax
25835     (type-tail %edx)  # => eax
25836     (type-equal? %ebx %eax)  # => eax
25837     3d/compare-eax-and 0/imm32/false
25838     0f 84/jump-if-= $check-mu-read-from-stream-stmt:error-invalid-target-type/disp32
25839 $check-mu-read-from-stream-stmt:check-too-many-inouts:
25840     # - check for too many inouts
25841     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
25842     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
25843     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
25844     3d/compare-eax-and 0/imm32/false
25845     0f 85/jump-if-!= $check-mu-read-from-stream-stmt:error-too-many-inouts/disp32
25846 $check-mu-read-from-stream-stmt:check-unexpected-output:
25847     # - check for any output
25848     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
25849     3d/compare-eax-and 0/imm32/false
25850     0f 85/jump-if-!= $check-mu-read-from-stream-stmt:error-unexpected-output/disp32
25851 $check-mu-read-from-stream-stmt:end:
25852     # . restore registers
25853     5f/pop-to-edi
25854     5e/pop-to-esi
25855     5b/pop-to-ebx
25856     5a/pop-to-edx
25857     59/pop-to-ecx
25858     58/pop-to-eax
25859     # . epilogue
25860     89/<- %esp 5/r32/ebp
25861     5d/pop-to-ebp
25862     c3/return
25864 $check-mu-read-from-stream-stmt:error-invalid-base-type:
25865     (write-buffered *(ebp+0x10) "fn ")
25866     8b/-> *(ebp+0xc) 0/r32/eax
25867     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25868     (write-buffered *(ebp+0x10) %eax)
25869     (write-buffered *(ebp+0x10) ": stmt read-from-stream: var '")
25870     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
25871     (write-buffered *(ebp+0x10) %eax)
25872     (write-buffered *(ebp+0x10) "' must be an addr to a stream\n")
25873     (flush *(ebp+0x10))
25874     (stop *(ebp+0x14) 1)
25875     # never gets here
25877 $check-mu-read-from-stream-stmt:error-too-few-inouts:
25878     (write-buffered *(ebp+0x10) "fn ")
25879     8b/-> *(ebp+0xc) 0/r32/eax
25880     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25881     (write-buffered *(ebp+0x10) %eax)
25882     (write-buffered *(ebp+0x10) ": stmt read-from-stream: too few inouts (2 required)\n")
25883     (flush *(ebp+0x10))
25884     (stop *(ebp+0x14) 1)
25885     # never gets here
25887 $check-mu-read-from-stream-stmt:error-target-type-not-address:
25888     (write-buffered *(ebp+0x10) "fn ")
25889     8b/-> *(ebp+0xc) 0/r32/eax
25890     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25891     (write-buffered *(ebp+0x10) %eax)
25892     (write-buffered *(ebp+0x10) ": stmt read-from-stream: target '")
25893     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
25894     (write-buffered *(ebp+0x10) %eax)
25895     (write-buffered *(ebp+0x10) "' must be an addr\n")
25896     (flush *(ebp+0x10))
25897     (stop *(ebp+0x14) 1)
25898     # never gets here
25900 $check-mu-read-from-stream-stmt:error-invalid-target-type:
25901     (write-buffered *(ebp+0x10) "fn ")
25902     8b/-> *(ebp+0xc) 0/r32/eax
25903     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25904     (write-buffered *(ebp+0x10) %eax)
25905     (write-buffered *(ebp+0x10) ": stmt read-from-stream: second inout '")
25906     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
25907     (write-buffered *(ebp+0x10) %eax)
25908     (write-buffered *(ebp+0x10) "' does not have the right type\n")
25909     (flush *(ebp+0x10))
25910     (stop *(ebp+0x14) 1)
25911     # never gets here
25913 $check-mu-read-from-stream-stmt:error-too-many-inouts:
25914     (write-buffered *(ebp+0x10) "fn ")
25915     8b/-> *(ebp+0xc) 0/r32/eax
25916     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25917     (write-buffered *(ebp+0x10) %eax)
25918     (write-buffered *(ebp+0x10) ": stmt read-from-stream: too many inouts (2 required)\n")
25919     (flush *(ebp+0x10))
25920     (stop *(ebp+0x14) 1)
25921     # never gets here
25923 $check-mu-read-from-stream-stmt:error-unexpected-output:
25924     (write-buffered *(ebp+0x10) "fn ")
25925     8b/-> *(ebp+0xc) 0/r32/eax
25926     (lookup *eax *(eax+4))  # Function-name Function-name => eax
25927     (write-buffered *(ebp+0x10) %eax)
25928     (write-buffered *(ebp+0x10) ": stmt read-from-stream: unexpected output\n")
25929     (flush *(ebp+0x10))
25930     (stop *(ebp+0x14) 1)
25931     # never gets here
25933 check-mu-write-to-stream-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
25934     # . prologue
25935     55/push-ebp
25936     89/<- %ebp 4/r32/esp
25937     # . save registers
25938     50/push-eax
25939     51/push-ecx
25940     52/push-edx
25941     53/push-ebx
25942     56/push-esi
25943     57/push-edi
25944     # esi = stmt
25945     8b/-> *(ebp+8) 6/r32/esi
25946     # - check for 0 inouts
25947     # var base/ecx: (addr var) = stmt->inouts->value
25948     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
25949 $check-mu-write-to-stream-stmt:check-no-inouts:
25950     3d/compare-eax-and 0/imm32
25951     0f 84/jump-if-= $check-mu-write-to-stream-stmt:error-too-few-inouts/disp32
25952     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
25953     89/<- %ecx 0/r32/eax
25954     # - check base type is (addr stream T)
25955     # var base-type/ebx: (addr type-tree) = lookup(base->type)
25956     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
25957     89/<- %ebx 0/r32/eax
25958 $check-mu-write-to-stream-stmt:check-base-is-compound:
25959     # if base-type is an atom, abort
25960     81 7/subop/compare *ebx 0/imm32/false  # Type-tree-is-atom
25961     0f 85/jump-if-!= $check-mu-write-to-stream-stmt:error-invalid-base-type/disp32
25962 $check-mu-write-to-stream-stmt:check-base-is-addr:
25963     # if type->left not addr, abort
25964     (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
25965     (simple-mu-type? %eax 2)  # addr => eax
25966     3d/compare-eax-and 0/imm32/false
25967     0f 84/jump-if-= $check-mu-write-to-stream-stmt:error-invalid-base-type/disp32
25968 $check-mu-write-to-stream-stmt:check-base-is-addr-to-stream:
25969     # base-type = base-type->right
25970     (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
25971     89/<- %ebx 0/r32/eax
25972     # ensure base-type->left == stream
25973     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
25974     (simple-mu-type? %eax 0xb)  # stream => eax
25975     3d/compare-eax-and 0/imm32/false
25976     0f 84/jump-if-= $check-mu-write-to-stream-stmt:error-invalid-base-type/disp32
25977     # - check target type is (addr T)
25978     # var target/ecx: (addr stmt-var) = stmt->inouts->next->value
25979     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
25980     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
25981 $check-mu-write-to-stream-stmt:check-single-inout:
25982     3d/compare-eax-and 0/imm32
25983     0f 84/jump-if-= $check-mu-write-to-stream-stmt:error-too-few-inouts/disp32
25984     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
25985     89/<- %ecx 0/r32/eax
25986     # var target-type/edx: (addr type-tree)
25987     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
25988     89/<- %edx 0/r32/eax
25989     # if target-type is an atom, it must be a literal or int
25990 $check-mu-write-to-stream-stmt:check-target-is-compound:
25991     81 7/subop/compare *edx 0/imm32/false  # Type-tree-is-atom
25992     0f 85/jump-if-!= $check-mu-write-to-stream-stmt:error-target-type-not-address/disp32
25993 $check-mu-write-to-stream-stmt:check-target-type:
25994     # target type must start with (addr ...)
25995     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
25996     (simple-mu-type? %eax 2)  # addr => eax
25997     3d/compare-eax-and 0/imm32/false
25998     0f 84/jump-if-= $check-mu-write-to-stream-stmt:error-target-type-not-address/disp32
25999     # if tail(base-type) != tail(target-type) abort
26000     (type-tail %ebx)  # => eax
26001     89/<- %ebx 0/r32/eax
26002     (type-tail %edx)  # => eax
26003     (type-equal? %ebx %eax)  # => eax
26004     3d/compare-eax-and 0/imm32/false
26005     0f 84/jump-if-= $check-mu-write-to-stream-stmt:error-invalid-target-type/disp32
26006 $check-mu-write-to-stream-stmt:check-too-many-inouts:
26007     # - check for too many inouts
26008     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
26009     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
26010     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
26011     3d/compare-eax-and 0/imm32/false
26012     0f 85/jump-if-!= $check-mu-write-to-stream-stmt:error-too-many-inouts/disp32
26013 $check-mu-write-to-stream-stmt:check-unexpected-output:
26014     # - check for any output
26015     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
26016     3d/compare-eax-and 0/imm32/false
26017     0f 85/jump-if-!= $check-mu-write-to-stream-stmt:error-unexpected-output/disp32
26018 $check-mu-write-to-stream-stmt:end:
26019     # . restore registers
26020     5f/pop-to-edi
26021     5e/pop-to-esi
26022     5b/pop-to-ebx
26023     5a/pop-to-edx
26024     59/pop-to-ecx
26025     58/pop-to-eax
26026     # . epilogue
26027     89/<- %esp 5/r32/ebp
26028     5d/pop-to-ebp
26029     c3/return
26031 $check-mu-write-to-stream-stmt:error-invalid-base-type:
26032     (write-buffered *(ebp+0x10) "fn ")
26033     8b/-> *(ebp+0xc) 0/r32/eax
26034     (lookup *eax *(eax+4))  # Function-name Function-name => eax
26035     (write-buffered *(ebp+0x10) %eax)
26036     (write-buffered *(ebp+0x10) ": stmt write-to-stream: var '")
26037     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
26038     (write-buffered *(ebp+0x10) %eax)
26039     (write-buffered *(ebp+0x10) "' must be an addr to a stream\n")
26040     (flush *(ebp+0x10))
26041     (stop *(ebp+0x14) 1)
26042     # never gets here
26044 $check-mu-write-to-stream-stmt:error-too-few-inouts:
26045     (write-buffered *(ebp+0x10) "fn ")
26046     8b/-> *(ebp+0xc) 0/r32/eax
26047     (lookup *eax *(eax+4))  # Function-name Function-name => eax
26048     (write-buffered *(ebp+0x10) %eax)
26049     (write-buffered *(ebp+0x10) ": stmt write-to-stream: too few inouts (2 required)\n")
26050     (flush *(ebp+0x10))
26051     (stop *(ebp+0x14) 1)
26052     # never gets here
26054 $check-mu-write-to-stream-stmt:error-target-type-not-address:
26055     (write-buffered *(ebp+0x10) "fn ")
26056     8b/-> *(ebp+0xc) 0/r32/eax
26057     (lookup *eax *(eax+4))  # Function-name Function-name => eax
26058     (write-buffered *(ebp+0x10) %eax)
26059     (write-buffered *(ebp+0x10) ": stmt write-to-stream: target '")
26060     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
26061     (write-buffered *(ebp+0x10) %eax)
26062     (write-buffered *(ebp+0x10) "' must be an addr\n")
26063     (flush *(ebp+0x10))
26064     (stop *(ebp+0x14) 1)
26065     # never gets here
26067 $check-mu-write-to-stream-stmt:error-invalid-target-type:
26068     (write-buffered *(ebp+0x10) "fn ")
26069     8b/-> *(ebp+0xc) 0/r32/eax
26070     (lookup *eax *(eax+4))  # Function-name Function-name => eax
26071     (write-buffered *(ebp+0x10) %eax)
26072     (write-buffered *(ebp+0x10) ": stmt write-to-stream: second inout '")
26073     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
26074     (write-buffered *(ebp+0x10) %eax)
26075     (write-buffered *(ebp+0x10) "' does not have the right type\n")
26076     (flush *(ebp+0x10))
26077     (stop *(ebp+0x14) 1)
26078     # never gets here
26080 $check-mu-write-to-stream-stmt:error-too-many-inouts:
26081     (write-buffered *(ebp+0x10) "fn ")
26082     8b/-> *(ebp+0xc) 0/r32/eax
26083     (lookup *eax *(eax+4))  # Function-name Function-name => eax
26084     (write-buffered *(ebp+0x10) %eax)
26085     (write-buffered *(ebp+0x10) ": stmt write-to-stream: too many inouts (2 required)\n")
26086     (flush *(ebp+0x10))
26087     (stop *(ebp+0x14) 1)
26088     # never gets here
26090 $check-mu-write-to-stream-stmt:error-unexpected-output:
26091     (write-buffered *(ebp+0x10) "fn ")
26092     8b/-> *(ebp+0xc) 0/r32/eax
26093     (lookup *eax *(eax+4))  # Function-name Function-name => eax
26094     (write-buffered *(ebp+0x10) %eax)
26095     (write-buffered *(ebp+0x10) ": stmt write-to-stream: unexpected output\n")
26096     (flush *(ebp+0x10))
26097     (stop *(ebp+0x14) 1)
26098     # never gets here
26100 check-mu-convert-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
26101     # . prologue
26102     55/push-ebp
26103     89/<- %ebp 4/r32/esp
26104     # . save registers
26105     50/push-eax
26106     51/push-ecx
26107     52/push-edx
26108     56/push-esi
26109     57/push-edi
26110 $check-mu-convert-stmt:get-output:
26111     # esi = stmt
26112     8b/-> *(ebp+8) 6/r32/esi
26113     # var output/edi: (addr stmt-var) = stmt->outputs
26114     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
26115     89/<- %edi 0/r32/eax
26116     # zero outputs
26117     3d/compare-eax-and 0/imm32
26118     0f 84/jump-if-= $check-mu-convert-stmt:error-no-output/disp32
26119     # > 1 output
26120     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
26121     3d/compare-eax-and 0/imm32
26122     0f 85/jump-if-!= $check-mu-convert-stmt:error-too-many-outputs/disp32
26123 $check-mu-convert-stmt:get-inout:
26124     # var inout/esi: (addr stmt-var) = stmt->inouts
26125     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
26126     89/<- %esi 0/r32/eax
26127     # zero inouts
26128     3d/compare-eax-and 0/imm32
26129     0f 84/jump-if-= $check-mu-convert-stmt:error-no-inout/disp32
26130     # > 1 inout
26131     (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
26132     3d/compare-eax-and 0/imm32
26133     0f 85/jump-if-!= $check-mu-convert-stmt:error-too-many-inouts/disp32
26134 $check-mu-convert-stmt:types:
26135     # var inout-type/ecx: (addr type-tree) = inout->value->type
26136     (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
26137     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
26138     89/<- %ecx 0/r32/eax
26139     # if (inout->is-deref?) inout-type = inout-type->payload
26140     8b/-> *(esi+0x10) 0/r32/eax  # Stmt-var-is-deref
26141     3d/compare-eax-and 0/imm32/false
26142     {
26143       74/jump-if-= break/disp8
26144       (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
26145       # if inout-type->right is null, t = inout-type->left
26146       81 7/subop/compare *(eax+0xc) 0/imm32  # Type-tree-right
26147       {
26148         75/jump-if-!= break/disp8
26149         (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
26150       }
26151       89/<- %ecx 0/r32/eax
26152     }
26153     # if input is not int or float, abort
26154     {
26155       (simple-mu-type? %ecx 1)  # int => eax
26156       3d/compare-eax-and 0/imm32/false
26157       75/jump-if-!= break/disp8
26158       (simple-mu-type? %ecx 0xf)  # float => eax
26159       3d/compare-eax-and 0/imm32/false
26160       75/jump-if-!= break/disp8
26161       e9/jump $check-mu-convert-stmt:error-invalid-inout-type/disp32
26162     }
26163     # if output not in register, abort
26164     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
26165     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
26166     3d/compare-eax-and 0/imm32
26167     0f 84/jump-if-= $check-mu-convert-stmt:error-output-not-in-register/disp32
26168     # var output-type/edx: (addr type-tree) = output->value->type
26169     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
26170     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
26171     89/<- %edx 0/r32/eax
26172     # if output is not int or float, abort
26173     {
26174       (simple-mu-type? %edx 1)  # int => eax
26175       3d/compare-eax-and 0/imm32/false
26176       75/jump-if-!= break/disp8
26177       (simple-mu-type? %edx 0xf)  # float => eax
26178       3d/compare-eax-and 0/imm32/false
26179       75/jump-if-!= break/disp8
26180       e9/jump $check-mu-convert-stmt:error-invalid-output-type/disp32
26181     }
26182     # if both are ints, abort
26183     {
26184       (simple-mu-type? %edx 1)  # int => eax
26185       3d/compare-eax-and 0/imm32/false
26186       74/jump-if-= break/disp8
26187       (simple-mu-type? %ecx 1)  # int => eax
26188       3d/compare-eax-and 0/imm32/false
26189       74/jump-if-= break/disp8
26190       e9/jump $check-mu-convert-stmt:error-int-to-int/disp32
26191     }
26192     # if both are floats, abort
26193     {
26194       (simple-mu-type? %edx 0xf)  # float => eax
26195       3d/compare-eax-and 0/imm32/false
26196       74/jump-if-= break/disp8
26197       (simple-mu-type? %ecx 0xf)  # float => eax
26198       3d/compare-eax-and 0/imm32/false
26199       74/jump-if-= break/disp8
26200       e9/jump $check-mu-convert-stmt:error-float-to-float/disp32
26201     }
26202 $check-mu-convert-stmt:end:
26203     # . restore registers
26204     5f/pop-to-edi
26205     5e/pop-to-esi
26206     5a/pop-to-edx
26207     59/pop-to-ecx
26208     58/pop-to-eax
26209     # . epilogue
26210     89/<- %esp 5/r32/ebp
26211     5d/pop-to-ebp
26212     c3/return
26214 $check-mu-convert-stmt:error-no-inout:
26215     (write-buffered *(ebp+0x10) "fn ")
26216     8b/-> *(ebp+0xc) 0/r32/eax
26217     (lookup *eax *(eax+4))  # Function-name Function-name => eax
26218     (write-buffered *(ebp+0x10) %eax)
26219     (write-buffered *(ebp+0x10) ": stmt 'convert' expects an inout\n")
26220     (flush *(ebp+0x10))
26221     (stop *(ebp+0x14) 1)
26222     # never gets here
26224 $check-mu-convert-stmt:error-too-many-inouts:
26225     (write-buffered *(ebp+0x10) "fn ")
26226     8b/-> *(ebp+0xc) 0/r32/eax
26227     (lookup *eax *(eax+4))  # Function-name Function-name => eax
26228     (write-buffered *(ebp+0x10) %eax)
26229     (write-buffered *(ebp+0x10) ": stmt 'convert' must have just one inout\n")
26230     (flush *(ebp+0x10))
26231     (stop *(ebp+0x14) 1)
26232     # never gets here
26234 $check-mu-convert-stmt:error-no-output:
26235     (write-buffered *(ebp+0x10) "fn ")
26236     8b/-> *(ebp+0xc) 0/r32/eax
26237     (lookup *eax *(eax+4))  # Function-name Function-name => eax
26238     (write-buffered *(ebp+0x10) %eax)
26239     (write-buffered *(ebp+0x10) ": stmt 'convert' expects an output\n")
26240     (flush *(ebp+0x10))
26241     (stop *(ebp+0x14) 1)
26242     # never gets here
26244 $check-mu-convert-stmt:error-output-not-in-register:
26245     (write-buffered *(ebp+0x10) "fn ")
26246     8b/-> *(ebp+0xc) 0/r32/eax
26247     (lookup *eax *(eax+4))  # Function-name Function-name => eax
26248     (write-buffered *(ebp+0x10) %eax)
26249     (write-buffered *(ebp+0x10) ": stmt convert: output '")
26250     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
26251     (lookup *eax *(eax+4))  # Var-name Var-name => eax
26252     (write-buffered *(ebp+0x10) %eax)
26253     (write-buffered *(ebp+0x10) "' not in a register\n")
26254     (flush *(ebp+0x10))
26255     (stop *(ebp+0x14) 1)
26256     # never gets here
26258 $check-mu-convert-stmt:error-too-many-outputs:
26259     (write-buffered *(ebp+0x10) "fn ")
26260     8b/-> *(ebp+0xc) 0/r32/eax
26261     (lookup *eax *(eax+4))  # Function-name Function-name => eax
26262     (write-buffered *(ebp+0x10) %eax)
26263     (write-buffered *(ebp+0x10) ": stmt 'convert' must have just one output\n")
26264     (flush *(ebp+0x10))
26265     (stop *(ebp+0x14) 1)
26266     # never gets here
26268 $check-mu-convert-stmt:error-invalid-inout-type:
26269     (write-buffered *(ebp+0x10) "fn ")
26270     8b/-> *(ebp+0xc) 0/r32/eax
26271     (lookup *eax *(eax+4))  # Function-name Function-name => eax
26272     (write-buffered *(ebp+0x10) %eax)
26273     (write-buffered *(ebp+0x10) ": stmt convert: inout '")
26274     (lookup *esi *(esi+4))  # Stmt-var-value Stmt-var-value => eax
26275     (lookup *eax *(eax+4))  # Var-name Var-name => eax
26276     (write-buffered *(ebp+0x10) %eax)
26277     (write-buffered *(ebp+0x10) "' must be an int or float\n")
26278     (flush *(ebp+0x10))
26279     (stop *(ebp+0x14) 1)
26280     # never gets here
26282 $check-mu-convert-stmt:error-invalid-output-type:
26283     (write-buffered *(ebp+0x10) "fn ")
26284     8b/-> *(ebp+0xc) 0/r32/eax
26285     (lookup *eax *(eax+4))  # Function-name Function-name => eax
26286     (write-buffered *(ebp+0x10) %eax)
26287     (write-buffered *(ebp+0x10) ": stmt convert: output '")
26288     (lookup *edi *(edi+4))  # Stmt-var-value Stmt-var-value => eax
26289     (lookup *eax *(eax+4))  # Var-name Var-name => eax
26290     (write-buffered *(ebp+0x10) %eax)
26291     (write-buffered *(ebp+0x10) "' must be an int or float\n")
26292     (flush *(ebp+0x10))
26293     (stop *(ebp+0x14) 1)
26294     # never gets here
26296 $check-mu-convert-stmt:error-int-to-int:
26297     (write-buffered *(ebp+0x10) "fn ")
26298     8b/-> *(ebp+0xc) 0/r32/eax
26299     (lookup *eax *(eax+4))  # Function-name Function-name => eax
26300     (write-buffered *(ebp+0x10) %eax)
26301     (write-buffered *(ebp+0x10) ": stmt convert: no need to convert int to int\n")
26302     (flush *(ebp+0x10))
26303     (stop *(ebp+0x14) 1)
26304     # never gets here
26306 $check-mu-convert-stmt:error-float-to-float:
26307     (write-buffered *(ebp+0x10) "fn ")
26308     8b/-> *(ebp+0xc) 0/r32/eax
26309     (lookup *eax *(eax+4))  # Function-name Function-name => eax
26310     (write-buffered *(ebp+0x10) %eax)
26311     (write-buffered *(ebp+0x10) ": stmt convert: no need to convert float to float\n")
26312     (flush *(ebp+0x10))
26313     (stop *(ebp+0x14) 1)
26314     # never gets here
26316 check-mu-call:  # stmt: (addr stmt), callee: (addr function), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
26317     # . prologue
26318     55/push-ebp
26319     89/<- %ebp 4/r32/esp
26320     # var type-parameters: (addr table (handle array byte) (addr type-tree) 8)
26321     68/push 0/imm32
26322     # var type-parameters-storage: (table (handle array byte) (addr type-tree) 8)
26323     81 5/subop/subtract %esp 0x60/imm32
26324     68/push 0x60/imm32/size
26325     68/push 0/imm32/read
26326     68/push 0/imm32/write
26327     # save a pointer to type-parameters-storage at type-parameters
26328     89/<- *(ebp-4) 4/r32/esp
26329     (clear-stream *(ebp-4))
26330     # . save registers
26331     50/push-eax
26332     51/push-ecx
26333     52/push-edx
26334     53/push-ebx
26335     56/push-esi
26336     57/push-edi
26337     # esi = stmt
26338     8b/-> *(ebp+8) 6/r32/esi
26339     # edi = callee
26340     8b/-> *(ebp+0xc) 7/r32/edi
26341     # var inouts/ecx: (addr stmt-var) = lookup(stmt->inouts)
26342     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
26343     89/<- %ecx 0/r32/eax
26344     # var expected/edx: (addr list var) = lookup(f->inouts)
26345     (lookup *(edi+8) *(edi+0xc))  # Function-inouts Function-inouts => eax
26346     89/<- %edx 0/r32/eax
26347     {
26348 $check-mu-call:check-for-inouts:
26349       # if (inouts == 0) break
26350       81 7/subop/compare %ecx 0/imm32
26351       0f 84/jump-if-= break/disp32
26352       # if (expected == 0) error
26353       81 7/subop/compare %edx 0/imm32
26354       0f 84/jump-if-= break/disp32
26355 $check-mu-call:check-null-addr:
26356       # if (inouts->value->name == "0") continue
26357       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
26358       (lookup *eax *(eax+4))  # Var-name Var-name => eax
26359       (string-equal? %eax "0")  # => eax
26360       3d/compare-eax-and 0/imm32/false
26361       0f 85/jump-if-!= $check-mu-call:continue-to-next-inout/disp32
26362 $check-mu-call:check-inout-type:
26363       # var t/ebx: (addr type-tree) = inouts->value->type
26364       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
26365       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
26366       89/<- %ebx 0/r32/eax
26367       # if (inouts->is-deref?) t = t->right
26368       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
26369       {
26370         74/jump-if-= break/disp8
26371         (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
26372         89/<- %ebx 0/r32/eax
26373         # if t->right is null, t = t->left
26374         81 7/subop/compare *(ebx+0xc) 0/imm32  # Type-tree-right
26375         75/jump-if-!= break/disp8
26376         (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
26377         89/<- %ebx 0/r32/eax
26378       }
26379       # var v2/eax: (addr v) = lookup(expected->value)
26380       (lookup *edx *(edx+4))  # List-value List-value => eax
26381       # var t2/eax: (addr type-tree) = lookup(v2->type)
26382       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
26383       # if (t != t2) error
26384       (type-match? %eax %ebx *(ebp-4))  # => eax
26385       3d/compare-eax-and 0/imm32/false
26386       {
26387         0f 85/jump-if-!= break/disp32
26388         (write-buffered *(ebp+0x14) "fn ")
26389         8b/-> *(ebp+0x10) 0/r32/eax
26390         (lookup *eax *(eax+4))  # Function-name Function-name => eax
26391         (write-buffered *(ebp+0x14) %eax)
26392         (write-buffered *(ebp+0x14) ": call ")
26393         (lookup *edi *(edi+4))  # Function-name Function-name => eax
26394         (write-buffered *(ebp+0x14) %eax)
26395         (write-buffered *(ebp+0x14) ": type for inout '")
26396         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
26397         (lookup *eax *(eax+4))  # Var-name Var-name => eax
26398         (write-buffered *(ebp+0x14) %eax)
26399         (write-buffered *(ebp+0x14) "' is not right\n")
26400         (flush *(ebp+0x14))
26401         (stop *(ebp+0x18) 1)
26402       }
26403 $check-mu-call:continue-to-next-inout:
26404       # inouts = lookup(inouts->next)
26405       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
26406       89/<- %ecx 0/r32/eax
26407       # expected = lookup(expected->next)
26408       (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
26409       89/<- %edx 0/r32/eax
26410       #
26411       e9/jump loop/disp32
26412     }
26413 $check-mu-call:check-inout-count:
26414     # if (inouts == expected) proceed
26415     39/compare %ecx 2/r32/edx
26416     {
26417       0f 84/jump-if-= break/disp32
26418       # exactly one of the two is null
26419       # if (inouts == 0) error("too many inouts")
26420       {
26421         81 7/subop/compare %ecx 0/imm32
26422         0f 84/jump-if-= break/disp32
26423         (write-buffered *(ebp+0x14) "fn ")
26424         8b/-> *(ebp+0x10) 0/r32/eax
26425         (lookup *eax *(eax+4))  # Function-name Function-name => eax
26426         (write-buffered *(ebp+0x14) %eax)
26427         (write-buffered *(ebp+0x14) ": call ")
26428         (lookup *edi *(edi+4))  # Function-name Function-name => eax
26429         (write-buffered *(ebp+0x14) %eax)
26430         (write-buffered *(ebp+0x14) ": too many inouts\n")
26431         (flush *(ebp+0x14))
26432         (stop *(ebp+0x18) 1)
26433       }
26434       # if (expected == 0) error("too few inouts")
26435       {
26436         81 7/subop/compare %edx 0/imm32
26437         0f 84/jump-if-= break/disp32
26438         (write-buffered *(ebp+0x14) "fn ")
26439         8b/-> *(ebp+0x10) 0/r32/eax
26440         (lookup *eax *(eax+4))  # Function-name Function-name => eax
26441         (write-buffered *(ebp+0x14) %eax)
26442         (write-buffered *(ebp+0x14) ": call ")
26443         (lookup *edi *(edi+4))  # Function-name Function-name => eax
26444         (write-buffered *(ebp+0x14) %eax)
26445         (write-buffered *(ebp+0x14) ": too few inouts\n")
26446         (flush *(ebp+0x14))
26447         (stop *(ebp+0x18) 1)
26448       }
26449     }
26450 $check-mu-call:check-outputs:
26451     # var outputs/ecx: (addr stmt-var) = lookup(stmt->outputs)
26452     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
26453     89/<- %ecx 0/r32/eax
26454     # var expected/edx: (addr list var) = lookup(f->outputs)
26455     (lookup *(edi+0x10) *(edi+0x14))  # Function-outputs Function-outputs => eax
26456     89/<- %edx 0/r32/eax
26457     {
26458 $check-mu-call:check-for-outputs:
26459       # if (outputs == 0) break
26460       81 7/subop/compare %ecx 0/imm32
26461       0f 84/jump-if-= break/disp32
26462       # if (expected == 0) error
26463       81 7/subop/compare %edx 0/imm32
26464       0f 84/jump-if-= break/disp32
26465 $check-mu-call:check-output-type:
26466       # var v/eax: (addr v) = lookup(outputs->value)
26467       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
26468       # var t/ebx: (addr type-tree) = lookup(v->type)
26469       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
26470       89/<- %ebx 0/r32/eax
26471       # if (outputs->is-deref?) t = t->right  # TODO: check that t->left is an addr
26472       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
26473       {
26474         74/jump-if-= break/disp8
26475         (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
26476         89/<- %ebx 0/r32/eax
26477       }
26478       # var v2/eax: (addr v) = lookup(expected->value)
26479       (lookup *edx *(edx+4))  # List-value List-value => eax
26480       # var t2/eax: (addr type-tree) = lookup(v2->type)
26481       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
26482       # if (t != t2) error
26483       (type-match? %eax %ebx *(ebp-4))  # => eax
26484       3d/compare-eax-and 0/imm32/false
26485       {
26486         0f 85/jump-if-!= break/disp32
26487         (write-buffered *(ebp+0x14) "fn ")
26488         8b/-> *(ebp+0x10) 0/r32/eax
26489         (lookup *eax *(eax+4))  # Function-name Function-name => eax
26490         (write-buffered *(ebp+0x14) %eax)
26491         (write-buffered *(ebp+0x14) ": call ")
26492         (lookup *edi *(edi+4))  # Function-name Function-name => eax
26493         (write-buffered *(ebp+0x14) %eax)
26494         (write-buffered *(ebp+0x14) ": type for output '")
26495         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
26496         (lookup *eax *(eax+4))  # Var-name Var-name => eax
26497         (write-buffered *(ebp+0x14) %eax)
26498         (write-buffered *(ebp+0x14) "' is not right\n")
26499         (flush *(ebp+0x14))
26500         (stop *(ebp+0x18) 1)
26501       }
26502 $check-mu-call:check-output-register:
26503       # var v/eax: (addr v) = lookup(outputs->value)
26504       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
26505       # var r/ebx: (addr array byte) = lookup(v->register)
26506       (lookup *(eax+18) *(eax+0x1c))  # Var-register Var-register => eax
26507       89/<- %ebx 0/r32/eax
26508       # if (r == 0) error
26509       3d/compare-eax-and 0/imm32
26510       {
26511         0f 85/jump-if-!= break/disp32
26512         (write-buffered *(ebp+0x14) "fn ")
26513         8b/-> *(ebp+0x10) 0/r32/eax
26514         (lookup *eax *(eax+4))  # Function-name Function-name => eax
26515         (write-buffered *(ebp+0x14) %eax)
26516         (write-buffered *(ebp+0x14) ": call ")
26517         (lookup *edi *(edi+4))  # Function-name Function-name => eax
26518         (write-buffered *(ebp+0x14) %eax)
26519         (write-buffered *(ebp+0x14) ": output '")
26520         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
26521         (lookup *eax *(eax+4))  # Var-name Var-name => eax
26522         (write-buffered *(ebp+0x14) %eax)
26523         (write-buffered *(ebp+0x14) "' is not in a register\n")
26524         (flush *(ebp+0x14))
26525         (stop *(ebp+0x18) 1)
26526       }
26527       # var v2/eax: (addr v) = lookup(expected->value)
26528       (lookup *edx *(edx+4))  # Stmt-var-value Stmt-var-value => eax
26529       # var r2/eax: (addr array byte) = lookup(v2->register)
26530       (lookup *(eax+18) *(eax+0x1c))  # Var-register Var-register => eax
26531       # if (r != r2) error
26532       (string-equal? %eax %ebx)  # => eax
26533       3d/compare-eax-and 0/imm32/false
26534       {
26535         0f 85/jump-if-!= break/disp32
26536         (write-buffered *(ebp+0x14) "fn ")
26537         8b/-> *(ebp+0x10) 0/r32/eax
26538         (lookup *eax *(eax+4))  # Function-name Function-name => eax
26539         (write-buffered *(ebp+0x14) %eax)
26540         (write-buffered *(ebp+0x14) ": call ")
26541         (lookup *edi *(edi+4))  # Function-name Function-name => eax
26542         (write-buffered *(ebp+0x14) %eax)
26543         (write-buffered *(ebp+0x14) ": register for output '")
26544         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
26545         (lookup *eax *(eax+4))  # Var-name Var-name => eax
26546         (write-buffered *(ebp+0x14) %eax)
26547         (write-buffered *(ebp+0x14) "' is not right\n")
26548         (flush *(ebp+0x14))
26549         (stop *(ebp+0x18) 1)
26550       }
26551 $check-mu-call:continue-to-next-output:
26552       # outputs = lookup(outputs->next)
26553       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
26554       89/<- %ecx 0/r32/eax
26555       # expected = lookup(expected->next)
26556       (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
26557       89/<- %edx 0/r32/eax
26558       #
26559       e9/jump loop/disp32
26560     }
26561 $check-mu-call:check-output-count:
26562     # if (outputs == expected) proceed
26563     39/compare %ecx 2/r32/edx
26564     {
26565       0f 84/jump-if-= break/disp32
26566       # exactly one of the two is null
26567       # if (outputs == 0) error("too many outputs")
26568       {
26569         81 7/subop/compare %ecx 0/imm32
26570         0f 84/jump-if-= break/disp32
26571         (write-buffered *(ebp+0x14) "fn ")
26572         8b/-> *(ebp+0x10) 0/r32/eax
26573         (lookup *eax *(eax+4))  # Function-name Function-name => eax
26574         (write-buffered *(ebp+0x14) %eax)
26575         (write-buffered *(ebp+0x14) ": call ")
26576         (lookup *edi *(edi+4))  # Function-name Function-name => eax
26577         (write-buffered *(ebp+0x14) %eax)
26578         (write-buffered *(ebp+0x14) ": too many outputs\n")
26579         (flush *(ebp+0x14))
26580         (stop *(ebp+0x18) 1)
26581       }
26582       # if (expected == 0) error("too few outputs")
26583       {
26584         81 7/subop/compare %edx 0/imm32
26585         0f 84/jump-if-= break/disp32
26586         (write-buffered *(ebp+0x14) "fn ")
26587         8b/-> *(ebp+0x10) 0/r32/eax
26588         (lookup *eax *(eax+4))  # Function-name Function-name => eax
26589         (write-buffered *(ebp+0x14) %eax)
26590         (write-buffered *(ebp+0x14) ": call ")
26591         (lookup *edi *(edi+4))  # Function-name Function-name => eax
26592         (write-buffered *(ebp+0x14) %eax)
26593         (write-buffered *(ebp+0x14) ": too few outputs\n")
26594         (flush *(ebp+0x14))
26595         (stop *(ebp+0x18) 1)
26596       }
26597     }
26598 $check-mu-call:end:
26599     # . restore registers
26600     5f/pop-to-edi
26601     5e/pop-to-esi
26602     5b/pop-to-ebx
26603     5a/pop-to-edx
26604     59/pop-to-ecx
26605     58/pop-to-eax
26606     # . reclaim locals exclusively on the stack
26607     81 0/subop/add %esp 0x70/imm32
26608     # . epilogue
26609     89/<- %esp 5/r32/ebp
26610     5d/pop-to-ebp
26611     c3/return
26613 # like type-equal? but takes literals type parameters into account
26614 type-match?:  # def: (addr type-tree), call: (addr type-tree), type-parameters: (addr table (handle array byte) (addr type-tree)) -> result/eax: boolean
26615     # . prologue
26616     55/push-ebp
26617     89/<- %ebp 4/r32/esp
26618     # if call is literal and def is numberlike, return true
26619     {
26620 $type-match?:check-literal-int:
26621       (simple-mu-type? *(ebp+0xc) 0)  # literal => eax
26622       3d/compare-eax-and 0/imm32/false
26623       74/jump-if-= break/disp8
26624       (mu-numberlike-output? *(ebp+8))  # => eax
26625       3d/compare-eax-and 0/imm32/false
26626       74/jump-if-= break/disp8
26627       b8/copy-to-eax 1/imm32/true
26628       e9/jump $type-match?:end/disp32
26629     }
26630     # if call is literal-string, match against (addr array byte)
26631     {
26632 $type-match?:check-literal-string:
26633       (simple-mu-type? *(ebp+0xc) 0x10)  # literal-string => eax
26634       3d/compare-eax-and 0/imm32/false
26635       74/jump-if-= break/disp8
26636       (type-component-match? *(ebp+8) Addr-type-string *(ebp+0x10))  # => eax
26637       e9/jump $type-match?:end/disp32
26638     }
26639 $type-match?:baseline:
26640     # otherwise fall back
26641     (type-component-match? *(ebp+8) *(ebp+0xc) *(ebp+0x10))  # => eax
26642 $type-match?:end:
26643     # . epilogue
26644     89/<- %esp 5/r32/ebp
26645     5d/pop-to-ebp
26646     c3/return
26648 type-component-match?:  # def: (addr type-tree), call: (addr type-tree), type-parameters: (addr table (handle array byte) (addr type-tree)) -> result/eax: boolean
26649     # . prologue
26650     55/push-ebp
26651     89/<- %ebp 4/r32/esp
26652     # . save registers
26653     51/push-ecx
26654     52/push-edx
26655     53/push-ebx
26656     # ecx = def
26657     8b/-> *(ebp+8) 1/r32/ecx
26658     # edx = call
26659     8b/-> *(ebp+0xc) 2/r32/edx
26660 $type-component-match?:compare-addr:
26661     # if (def == call) return true
26662     8b/-> %ecx 0/r32/eax  # Var-type
26663     39/compare %edx 0/r32/eax  # Var-type
26664     b8/copy-to-eax 1/imm32/true
26665     0f 84/jump-if-= $type-component-match?:end/disp32
26666     # if (def == 0) return false
26667     b8/copy-to-eax 0/imm32/false
26668     81 7/subop/compare %ecx 0/imm32  # Type-tree-is-atom
26669     0f 84/jump-if-= $type-component-match?:end/disp32
26670     # if (call == 0) return false
26671     81 7/subop/compare %edx 0/imm32  # Type-tree-is-atom
26672     0f 84/jump-if-= $type-component-match?:end/disp32
26673     # if def is a type parameter, just check in type-parameters
26674     {
26675 $type-component-match?:check-type-parameter:
26676       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
26677       74/jump-if-= break/disp8
26678       81 7/subop/compare *(ecx+4) 0xa/imm32/type-parameter  # Type-tree-value
26679       75/jump-if-!= break/disp8
26680 $type-component-match?:type-parameter:
26681       (type-parameter-match? *(ecx+8) *(ecx+0xc)  %edx  *(ebp+0x10))  # => eax
26682       e9/jump $type-component-match?:end/disp32
26683     }
26684     # if def is a list containing just a type parameter, just check in type-parameters
26685     {
26686 $type-component-match?:check-list-type-parameter:
26687       # if def is a list..
26688       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
26689       75/jump-if-!= break/disp8
26690       #   ..that's a singleton
26691       81 7/subop/compare *(ecx+0xc) 0/imm32  # Type-tree-left
26692       75/jump-if-!= break/disp8
26693       #   ..and whose head is a type parameter
26694       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
26695       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
26696       74/jump-if-= break/disp8
26697       81 7/subop/compare *(eax+4) 0xa/imm32/type-parameter  # Type-tree-value
26698       75/jump-if-!= break/disp8
26699 $type-component-match?:list-type-parameter:
26700       (type-parameter-match? *(eax+8) *(eax+0xc)  %edx  *(ebp+0x10))  # => eax
26701       e9/jump $type-component-match?:end/disp32
26702     }
26703 $type-component-match?:compare-atom-state:
26704     # if (def->is-atom? != call->is-atom?) return false
26705     8b/-> *ecx 3/r32/ebx  # Type-tree-is-atom
26706     39/compare *edx 3/r32/ebx  # Type-tree-is-atom
26707     b8/copy-to-eax 0/imm32/false
26708     0f 85/jump-if-!= $type-component-match?:end/disp32
26709     # if def->is-atom? return (def->value == call->value)
26710     {
26711 $type-component-match?:check-atom:
26712       81 7/subop/compare %ebx 0/imm32/false
26713       74/jump-if-= break/disp8
26714 $type-component-match?:is-atom:
26715       8b/-> *(ecx+4) 0/r32/eax  # Type-tree-value
26716       39/compare *(edx+4) 0/r32/eax  # Type-tree-value
26717       0f 94/set-if-= %al
26718       25/and-eax-with 0xff/imm32
26719       e9/jump $type-component-match?:end/disp32
26720     }
26721 $type-component-match?:check-left:
26722     # if (!type-component-match?(def->left, call->left)) return false
26723     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
26724     89/<- %ebx 0/r32/eax
26725     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
26726     (type-component-match? %ebx %eax *(ebp+0x10))  # => eax
26727     3d/compare-eax-and 0/imm32/false
26728     74/jump-if-= $type-component-match?:end/disp8
26729 $type-component-match?:check-right:
26730     # return type-component-match?(def->right, call->right)
26731     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
26732     89/<- %ebx 0/r32/eax
26733     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
26734     (type-component-match? %ebx %eax *(ebp+0x10))  # => eax
26735 $type-component-match?:end:
26736     # . restore registers
26737     5b/pop-to-ebx
26738     5a/pop-to-edx
26739     59/pop-to-ecx
26740     # . epilogue
26741     89/<- %esp 5/r32/ebp
26742     5d/pop-to-ebp
26743     c3/return
26745 type-parameter-match?:  # type-parameter-name: (handle array byte), type: (addr type-tree), type-parameters: (addr table (handle array byte) (addr type-tree)) -> result/eax: boolean
26746     # . prologue
26747     55/push-ebp
26748     89/<- %ebp 4/r32/esp
26749     # . save registers
26750     51/push-ecx
26751     #
26752     (get-or-insert-handle *(ebp+0x14)  *(ebp+8) *(ebp+0xc)  0xc)  # => eax
26753     # if parameter wasn't saved, save it
26754     {
26755       81 7/subop/compare *eax 0/imm32
26756       75/jump-if-!= break/disp8
26757       8b/-> *(ebp+0x10) 1/r32/ecx
26758       89/<- *eax 1/r32/ecx
26759     }
26760     #
26761     (type-equal? *(ebp+0x10) *eax)  # => eax
26762 $type-parameter-match?:end:
26763     # . restore registers
26764     59/pop-to-ecx
26765     # . epilogue
26766     89/<- %esp 5/r32/ebp
26767     5d/pop-to-ebp
26768     c3/return
26770 size-of:  # v: (addr var) -> result/eax: int
26771     # . prologue
26772     55/push-ebp
26773     89/<- %ebp 4/r32/esp
26774     # . save registers
26775     51/push-ecx
26776     # var t/ecx: (addr type-tree) = lookup(v->type)
26777     8b/-> *(ebp+8) 1/r32/ecx
26778 #?     (write-buffered Stderr "size-of ")
26779 #?     (write-int32-hex-buffered Stderr %ecx)
26780 #?     (write-buffered Stderr Newline)
26781 #?     (write-buffered Stderr "type allocid: ")
26782 #?     (write-int32-hex-buffered Stderr *(ecx+8))
26783 #?     (write-buffered Stderr Newline)
26784 #?     (flush Stderr)
26785     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
26786     89/<- %ecx 0/r32/eax
26787     # if mu-array?(t) return size-of-array(t)
26788     {
26789       (mu-array? %ecx)  # => eax
26790       3d/compare-eax-and 0/imm32/false
26791       74/jump-if-= break/disp8
26792       (size-of-array %ecx)  # => eax
26793       eb/jump $size-of:end/disp8
26794     }
26795     # if mu-stream?(t) return size-of-stream(t)
26796     {
26797       (mu-stream? %ecx)  # => eax
26798       3d/compare-eax-and 0/imm32/false
26799       74/jump-if-= break/disp8
26800       (size-of-stream %ecx)  # => eax
26801       eb/jump $size-of:end/disp8
26802     }
26803     # if (!t->is-atom?) t = lookup(t->left)
26804     {
26805       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
26806       75/jump-if-!= break/disp8
26807       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
26808       89/<- %ecx 0/r32/eax
26809     }
26810     # TODO: assert t->is-atom?
26811     (size-of-type-id *(ecx+4))  # Type-tree-value => eax
26812 $size-of:end:
26813     # . restore registers
26814     59/pop-to-ecx
26815     # . epilogue
26816     89/<- %esp 5/r32/ebp
26817     5d/pop-to-ebp
26818     c3/return
26820 size-of-deref:  # v: (addr var) -> result/eax: int
26821     # . prologue
26822     55/push-ebp
26823     89/<- %ebp 4/r32/esp
26824     # . save registers
26825     51/push-ecx
26826     # var t/ecx: (addr type-tree) = lookup(v->type)
26827     8b/-> *(ebp+8) 1/r32/ecx
26828     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
26829     89/<- %ecx 0/r32/eax
26830     # TODO: assert(t is an addr)
26831     # t = lookup(t->right)
26832     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
26833     89/<- %ecx 0/r32/eax
26834     # if mu-array?(t) return size-of-array(t)
26835     {
26836       (mu-array? %ecx)  # => eax
26837       3d/compare-eax-and 0/imm32/false
26838       74/jump-if-= break/disp8
26839       (size-of-array %ecx)  # => eax
26840       eb/jump $size-of-deref:end/disp8
26841     }
26842     # if mu-stream?(t) return size-of-stream(t)
26843     {
26844       (mu-stream? %ecx)  # => eax
26845       3d/compare-eax-and 0/imm32/false
26846       74/jump-if-= break/disp8
26847       (size-of-stream %ecx)  # => eax
26848       eb/jump $size-of-deref:end/disp8
26849     }
26850     # if (!t->is-atom?) t = lookup(t->left)
26851     {
26852       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
26853       75/jump-if-!= break/disp8
26854       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
26855       89/<- %ecx 0/r32/eax
26856     }
26857     # TODO: assert t->is-atom?
26858     (size-of-type-id *(ecx+4))  # Type-tree-value => eax
26859 $size-of-deref:end:
26860     # . restore registers
26861     59/pop-to-ecx
26862     # . epilogue
26863     89/<- %esp 5/r32/ebp
26864     5d/pop-to-ebp
26865     c3/return
26867 mu-array?:  # t: (addr type-tree) -> result/eax: boolean
26868     # . prologue
26869     55/push-ebp
26870     89/<- %ebp 4/r32/esp
26871     # . save registers
26872     51/push-ecx
26873     # ecx = t
26874     8b/-> *(ebp+8) 1/r32/ecx
26875     # if t->is-atom?, return false
26876     81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
26877     75/jump-if-!= $mu-array?:return-false/disp8
26878     # if !t->left->is-atom?, return false
26879     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
26880     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
26881     74/jump-if-= $mu-array?:return-false/disp8
26882     # return t->left->value == array
26883     81 7/subop/compare *(eax+4) 3/imm32/array-type-id  # Type-tree-value
26884     0f 94/set-if-= %al
26885     25/and-eax-with 0xff/imm32
26886     eb/jump $mu-array?:end/disp8
26887 $mu-array?:return-false:
26888     b8/copy-to-eax 0/imm32/false
26889 $mu-array?:end:
26890     # . restore registers
26891     59/pop-to-ecx
26892     # . epilogue
26893     89/<- %esp 5/r32/ebp
26894     5d/pop-to-ebp
26895     c3/return
26897 # size of a statically allocated array where the size is part of the type expression
26898 size-of-array:  # a: (addr type-tree) -> result/eax: int
26899     # . prologue
26900     55/push-ebp
26901     89/<- %ebp 4/r32/esp
26902     # . save registers
26903     51/push-ecx
26904     52/push-edx
26905     #
26906     8b/-> *(ebp+8) 1/r32/ecx
26907     # TODO: assert that a->left is 'array'
26908     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
26909     89/<- %ecx 0/r32/eax
26910     # var elem-type/edx: type-id = a->right->left->value
26911     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
26912     8b/-> *(eax+4) 2/r32/edx  # Type-tree-value
26913     # TODO: assert that a->right->right->left->value == size
26914     # var array-size/ecx: int = a->right->right->left->value-size
26915     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
26916     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
26917     8b/-> *(eax+8) 1/r32/ecx  # Type-tree-value-size
26918     # return 4 + array-size * size-of(elem-type)
26919     (size-of-type-id-as-array-element %edx)  # => eax
26920     f7 4/subop/multiply-into-edx-eax %ecx
26921     05/add-to-eax 4/imm32  # for array size
26922     # TODO: check edx for overflow
26923 $size-of-array:end:
26924     # . restore registers
26925     5a/pop-to-edx
26926     59/pop-to-ecx
26927     # . epilogue
26928     89/<- %esp 5/r32/ebp
26929     5d/pop-to-ebp
26930     c3/return
26932 mu-stream?:  # t: (addr type-tree) -> result/eax: boolean
26933     # . prologue
26934     55/push-ebp
26935     89/<- %ebp 4/r32/esp
26936     # . save registers
26937     51/push-ecx
26938     # ecx = t
26939     8b/-> *(ebp+8) 1/r32/ecx
26940     # if t->is-atom?, return false
26941     81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
26942     75/jump-if-!= $mu-stream?:return-false/disp8
26943     # if !t->left->is-atom?, return false
26944     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
26945     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
26946     74/jump-if-= $mu-stream?:return-false/disp8
26947     # return t->left->value == stream
26948     81 7/subop/compare *(eax+4) 0xb/imm32/stream-type-id  # Type-tree-value
26949     0f 94/set-if-= %al
26950     25/and-eax-with 0xff/imm32
26951     eb/jump $mu-stream?:end/disp8
26952 $mu-stream?:return-false:
26953     b8/copy-to-eax 0/imm32/false
26954 $mu-stream?:end:
26955     # . restore registers
26956     59/pop-to-ecx
26957     # . epilogue
26958     89/<- %esp 5/r32/ebp
26959     5d/pop-to-ebp
26960     c3/return
26962 # size of a statically allocated stream where the size is part of the type expression
26963 size-of-stream:  # a: (addr type-tree) -> result/eax: int
26964     # . prologue
26965     55/push-ebp
26966     89/<- %ebp 4/r32/esp
26967     #
26968     (size-of-array *(ebp+8))  # assumes we ignore the actual type name 'array' in the type
26969     05/add-to-eax 8/imm32  # for read/write pointers
26970 $size-of-stream:end:
26971     # . epilogue
26972     89/<- %esp 5/r32/ebp
26973     5d/pop-to-ebp
26974     c3/return
26976 size-of-type-id:  # t: type-id -> result/eax: int
26977     # . prologue
26978     55/push-ebp
26979     89/<- %ebp 4/r32/esp
26980     # . save registers
26981     51/push-ecx
26982     # var out/ecx: (handle typeinfo)
26983     68/push 0/imm32
26984     68/push 0/imm32
26985     89/<- %ecx 4/r32/esp
26986     # eax = t
26987     8b/-> *(ebp+8) 0/r32/eax
26988     # if t is a literal, return 0
26989     3d/compare-eax-and 0/imm32
26990     0f 84/jump-if-= $size-of-type-id:end/disp32  # eax changes type from type-id to int
26991     # if t is a byte, return 4 (because we don't really support non-multiples of 4)
26992     3d/compare-eax-and 8/imm32/byte
26993     {
26994       75/jump-if-!= break/disp8
26995       b8/copy-to-eax 4/imm32
26996       eb/jump $size-of-type-id:end/disp8
26997     }
26998     # if t is a handle, return 8
26999     3d/compare-eax-and 4/imm32/handle
27000     {
27001       75/jump-if-!= break/disp8
27002       b8/copy-to-eax 8/imm32
27003       eb/jump $size-of-type-id:end/disp8  # eax changes type from type-id to int
27004     }
27005     # if t is a slice, return 8
27006     3d/compare-eax-and 0xc/imm32/slice
27007     {
27008       75/jump-if-!= break/disp8
27009       b8/copy-to-eax 8/imm32
27010       eb/jump $size-of-type-id:end/disp8  # eax changes type from type-id to int
27011     }
27012     # if t is a user-defined type, return its size
27013     # TODO: support non-atom type
27014     (find-typeinfo %eax %ecx)
27015     {
27016       81 7/subop/compare *ecx 0/imm32
27017       74/jump-if-= break/disp8
27018 $size-of-type-id:user-defined:
27019       (lookup *ecx *(ecx+4))  # => eax
27020       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
27021       eb/jump $size-of-type-id:end/disp8
27022     }
27023     # otherwise return the word size
27024     b8/copy-to-eax 4/imm32
27025 $size-of-type-id:end:
27026     # . reclaim locals
27027     81 0/subop/add %esp 8/imm32
27028     # . restore registers
27029     59/pop-to-ecx
27030     # . epilogue
27031     89/<- %esp 5/r32/ebp
27032     5d/pop-to-ebp
27033     c3/return
27035 # Minor violation of our type system since it returns an addr. But we could
27036 # replace it with a handle some time.
27037 # Returns null if t is an atom.
27038 type-tail:  # t: (addr type-tree) -> out/eax: (addr type-tree)
27039     # . prologue
27040     55/push-ebp
27041     89/<- %ebp 4/r32/esp
27042     # . save registers
27043     51/push-ecx
27044     # eax = 0
27045     b8/copy-to-eax 0/imm32
27046     # ecx = t
27047     8b/-> *(ebp+8) 1/r32/ecx
27048 $type-tail:check-atom:
27049     # if t->is-atom? return 0
27050     81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
27051     0f 85/jump-if-!= $type-tail:end/disp32
27052     # var tail = t->right
27053     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
27054     89/<- %ecx 0/r32/eax
27055 $type-tail:check-singleton:
27056     # if (tail->right == 0) return tail->left
27057     {
27058       81 7/subop/compare *(ecx+0xc) 0/imm32  # Type-tree-right
27059       75/jump-if-!= break/disp8
27060       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
27061       e9/jump $type-tail:end/disp32
27062     }
27063     # if tail->right->left is an array-capacity, return tail->left
27064     {
27065 $type-tail:check-array-capacity:
27066       (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
27067       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
27068       75/jump-if-!= break/disp8
27069 $type-tail:check-array-capacity-1:
27070       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
27071       3d/compare-eax-and 0/imm32
27072       74/jump-if-= break/disp8
27073 $type-tail:check-array-capacity-2:
27074       (simple-mu-type? %eax 9)  # array-capacity => eax
27075       3d/compare-eax-and 0/imm32/false
27076       74/jump-if-= break/disp8
27077 $type-tail:array-capacity:
27078       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
27079       eb/jump $type-tail:end/disp8
27080     }
27081 $type-tail:check-compound-left:
27082     # if !tail->left->is-atom? return tail->left
27083     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
27084     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
27085     74/jump-if-= $type-tail:end/disp8
27086 $type-tail:return-tail:
27087     # return tail
27088     89/<- %eax 1/r32/ecx
27089 $type-tail:end:
27090     # . restore registers
27091     59/pop-to-ecx
27092     # . epilogue
27093     89/<- %esp 5/r32/ebp
27094     5d/pop-to-ebp
27095     c3/return
27097 type-equal?:  # a: (addr type-tree), b: (addr type-tree) -> result/eax: boolean
27098     # . prologue
27099     55/push-ebp
27100     89/<- %ebp 4/r32/esp
27101     # . save registers
27102     51/push-ecx
27103     52/push-edx
27104     53/push-ebx
27105     # ecx = a
27106     8b/-> *(ebp+8) 1/r32/ecx
27107     # edx = b
27108     8b/-> *(ebp+0xc) 2/r32/edx
27109 $type-equal?:compare-addr:
27110     # if (a == b) return true
27111     8b/-> %ecx 0/r32/eax  # Var-type
27112     39/compare %edx 0/r32/eax  # Var-type
27113     b8/copy-to-eax 1/imm32/true
27114     0f 84/jump-if-= $type-equal?:end/disp32
27115 $type-equal?:compare-null-a:
27116     # if (a == 0) return false
27117     b8/copy-to-eax 0/imm32/false
27118     81 7/subop/compare %ecx 0/imm32
27119     0f 84/jump-if-= $type-equal?:end/disp32
27120 $type-equal?:compare-null-b:
27121     # if (b == 0) return false
27122     81 7/subop/compare %edx 0/imm32
27123     0f 84/jump-if-= $type-equal?:end/disp32
27124 $type-equal?:compare-atom-state:
27125     # if (a->is-atom? != b->is-atom?) return false
27126     8b/-> *ecx 3/r32/ebx  # Type-tree-is-atom
27127     39/compare *edx 3/r32/ebx  # Type-tree-is-atom
27128     b8/copy-to-eax 0/imm32/false
27129     0f 85/jump-if-!= $type-equal?:end/disp32
27130     # if a->is-atom? return (a->value == b->value)
27131     {
27132 $type-equal?:check-atom:
27133       81 7/subop/compare %ebx 0/imm32/false
27134       74/jump-if-= break/disp8
27135 $type-equal?:is-atom:
27136       8b/-> *(ecx+4) 0/r32/eax  # Type-tree-value
27137       39/compare *(edx+4) 0/r32/eax  # Type-tree-value
27138       0f 94/set-if-= %al
27139       25/and-eax-with 0xff/imm32
27140       e9/jump $type-equal?:end/disp32
27141     }
27142 $type-equal?:check-left:
27143     # if (!type-equal?(a->left, b->left)) return false
27144     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
27145     89/<- %ebx 0/r32/eax
27146     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
27147     (type-equal? %eax %ebx)  # => eax
27148     3d/compare-eax-and 0/imm32/false
27149     74/jump-if-= $type-equal?:end/disp8
27150 $type-equal?:check-right:
27151     # return type-equal?(a->right, b->right)
27152     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
27153     89/<- %ebx 0/r32/eax
27154     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
27155     (type-equal? %eax %ebx)  # => eax
27156 $type-equal?:end:
27157     # . restore registers
27158     5b/pop-to-ebx
27159     5a/pop-to-edx
27160     59/pop-to-ecx
27161     # . epilogue
27162     89/<- %esp 5/r32/ebp
27163     5d/pop-to-ebp
27164     c3/return
27166 #######################################################
27167 # Code-generation
27168 #######################################################
27170 == data
27172 # Global state added to each var record when performing code-generation.
27173 Curr-local-stack-offset:  # (addr int)
27174     0/imm32
27176 == code
27178 # We may not need to pass err/ed everywhere here. I think they're relics of Mu
27179 # getting type checks later in life.
27180 # But we do need them for runtime checks, particularly array index bounds checks.
27181 # So perhaps it's not worth taking them out. They're a safety net.
27183 emit-subx:  # out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
27184     # . prologue
27185     55/push-ebp
27186     89/<- %ebp 4/r32/esp
27187     # . save registers
27188     50/push-eax
27189     # var curr/eax: (addr function) = *Program->functions
27190     (lookup *_Program-functions *_Program-functions->payload)  # => eax
27191     {
27192       # if (curr == null) break
27193       3d/compare-eax-and 0/imm32
27194       0f 84/jump-if-= break/disp32
27195       (emit-subx-function *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))
27196       # curr = lookup(curr->next)
27197       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
27198       e9/jump loop/disp32
27199     }
27200 $emit-subx:end:
27201     # . restore registers
27202     58/pop-to-eax
27203     # . epilogue
27204     89/<- %esp 5/r32/ebp
27205     5d/pop-to-ebp
27206     c3/return
27208 emit-subx-function:  # out: (addr buffered-file), f: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
27209     # . prologue
27210     55/push-ebp
27211     89/<- %ebp 4/r32/esp
27212     # some preprocessing
27213     (populate-mu-type-offsets-in-inouts *(ebp+0xc))
27214     # . save registers
27215     50/push-eax
27216     51/push-ecx
27217     52/push-edx
27218     # initialize some global state
27219     c7 0/subop/copy *Curr-block-depth 1/imm32  # Important: keep this in sync with the parse phase
27220     c7 0/subop/copy *Curr-local-stack-offset 0/imm32
27221     # ecx = f
27222     8b/-> *(ebp+0xc) 1/r32/ecx
27223     # var vars/edx: (stack (addr var) 256)
27224     81 5/subop/subtract %esp 0xc00/imm32
27225     68/push 0xc00/imm32/size
27226     68/push 0/imm32/top
27227     89/<- %edx 4/r32/esp
27228     # var name/eax: (addr array byte) = lookup(f->name)
27229     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
27230     #
27231     (write-buffered *(ebp+8) %eax)
27232     (write-buffered *(ebp+8) ":\n")
27233     (emit-subx-prologue *(ebp+8))
27234     # var body/eax: (addr block) = lookup(f->body)
27235     (lookup *(ecx+0x18) *(ecx+0x1c))  # Function-body Function-body => eax
27236     #
27237     (emit-subx-block *(ebp+8) %eax %edx *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
27238     (emit-subx-epilogue *(ebp+8))
27239     # TODO: validate that *Curr-block-depth and *Curr-local-stack-offset have
27240     # been cleaned up
27241 $emit-subx-function:end:
27242     # . reclaim locals
27243     81 0/subop/add %esp 0xc08/imm32
27244     # . restore registers
27245     5a/pop-to-edx
27246     59/pop-to-ecx
27247     58/pop-to-eax
27248     # . epilogue
27249     89/<- %esp 5/r32/ebp
27250     5d/pop-to-ebp
27251     c3/return
27253 populate-mu-type-offsets-in-inouts:  # f: (addr function)
27254     # . prologue
27255     55/push-ebp
27256     89/<- %ebp 4/r32/esp
27257     # . save registers
27258     50/push-eax
27259     51/push-ecx
27260     52/push-edx
27261     53/push-ebx
27262     57/push-edi
27263     # var next-offset/edx: int = 8
27264     ba/copy-to-edx 8/imm32
27265     # var curr/ecx: (addr list var) = lookup(f->inouts)
27266     8b/-> *(ebp+8) 1/r32/ecx
27267     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
27268     89/<- %ecx 0/r32/eax
27269     {
27270 $populate-mu-type-offsets-in-inouts:loop:
27271       81 7/subop/compare %ecx 0/imm32
27272       74/jump-if-= break/disp8
27273       # var v/ebx: (addr var) = lookup(curr->value)
27274       (lookup *ecx *(ecx+4))  # List-value List-value => eax
27275       89/<- %ebx 0/r32/eax
27276 #?       (lookup *ebx *(ebx+4))
27277 #?       (write-buffered Stderr "setting offset of fn inout ")
27278 #?       (write-buffered Stderr %eax)
27279 #?       (write-buffered Stderr "@")
27280 #?       (write-int32-hex-buffered Stderr %ebx)
27281 #?       (write-buffered Stderr " to ")
27282 #?       (write-int32-hex-buffered Stderr %edx)
27283 #?       (write-buffered Stderr Newline)
27284 #?       (flush Stderr)
27285       # v->offset = next-offset
27286       89/<- *(ebx+0x14) 2/r32/edx  # Var-offset
27287       # next-offset += size-of(v)
27288       (size-of %ebx)  # => eax
27289       01/add-to %edx 0/r32/eax
27290       # curr = lookup(curr->next)
27291       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
27292       89/<- %ecx 0/r32/eax
27293       #
27294       eb/jump loop/disp8
27295     }
27296 $populate-mu-type-offsets-in-inouts:end:
27297     # . restore registers
27298     5f/pop-to-edi
27299     5b/pop-to-ebx
27300     5a/pop-to-edx
27301     59/pop-to-ecx
27302     58/pop-to-eax
27303     # . epilogue
27304     89/<- %esp 5/r32/ebp
27305     5d/pop-to-ebp
27306     c3/return
27308 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)
27309     # . prologue
27310     55/push-ebp
27311     89/<- %ebp 4/r32/esp
27312     # . save registers
27313     50/push-eax
27314     51/push-ecx
27315     53/push-ebx
27316     56/push-esi
27317     # esi = stmts
27318     8b/-> *(ebp+0xc) 6/r32/esi
27319     #
27320     {
27321 $emit-subx-stmt-list:loop:
27322       81 7/subop/compare %esi 0/imm32
27323       0f 84/jump-if-= break/disp32
27324       # var curr-stmt/ecx: (addr stmt) = lookup(stmts->value)
27325       (lookup *esi *(esi+4))  # List-value List-value => eax
27326       89/<- %ecx 0/r32/eax
27327       {
27328 $emit-subx-stmt-list:check-for-block:
27329         81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
27330         75/jump-if-!= break/disp8
27331 $emit-subx-stmt-list:block:
27332         (emit-subx-block *(ebp+8) %ecx *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
27333       }
27334       {
27335 $emit-subx-stmt-list:check-for-stmt:
27336         81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
27337         0f 85/jump-if-!= break/disp32
27338 $emit-subx-stmt-list:stmt1:
27339         {
27340           (mu-branch? %ecx)  # => eax
27341           3d/compare-eax-and 0/imm32/false
27342           0f 84/jump-if-= break/disp32
27343 $emit-subx-stmt-list:branch-stmt:
27344           # unconditional return {{{
27345           {
27346 $emit-subx-stmt-list:return:
27347             # if (!string-equal?(curr-stmt->operation, "return")) break
27348             (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
27349             (string-equal? %eax "return")  # => eax
27350             3d/compare-eax-and 0/imm32/false
27351             0f 84/jump-if-= break/disp32
27352             #
27353             (emit-outputs *(ebp+8) %ecx *(ebp+0x14))
27354             (emit-cleanup-code-for-non-outputs *(ebp+8) *(ebp+0x10) *(ebp+0x14))
27355             # emit jump to end of function
27356             # getting at the name of the label is challenging
27357             (emit-indent *(ebp+8) *Curr-block-depth)
27358             (write-buffered *(ebp+8) "e9/jump ")
27359             # var b/eax: (addr array byte) = fn->body->var->name
27360             8b/-> *(ebp+0x14) 0/r32/eax
27361             (lookup *(eax+0x18) *(eax+0x1c))  # Function-body Function-body => eax
27362             (lookup *(eax+0xc) *(eax+0x10))  # Block-var Block-var => eax
27363             (lookup *eax *(eax+4))  # Var-name Var-name => eax
27364             (write-buffered *(ebp+8) %eax)
27365             (write-buffered *(ebp+8) ":break/disp32\n")
27366             e9/jump $emit-subx-stmt-list:clean-up/disp32
27367           }
27368           # }}}
27369           # unconditional loops {{{
27370           {
27371             # if (!string-equal?(var->operation, "loop")) break
27372             (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
27373             (string-equal? %eax "loop")  # => eax
27374             3d/compare-eax-and 0/imm32/false
27375             0f 84/jump-if-= break/disp32
27376 $emit-subx-stmt-list:unconditional-loop:
27377             81 7/subop/compare *(ecx+0xc) 0/imm32  # Stmt1-inouts
27378             # simple unconditional loops without a target
27379             {
27380               0f 85/jump-if-!= break/disp32
27381 $emit-subx-stmt-list:zero-arg-unconditional-loop:
27382               (emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth)
27383               (emit-indent *(ebp+8) *Curr-block-depth)
27384               (write-buffered *(ebp+8) "e9/jump loop/disp32")
27385               (write-buffered *(ebp+8) Newline)
27386               e9/jump $emit-subx-stmt-list:clean-up/disp32  # skip remaining statements; they're dead code
27387             }
27388             # unconditional loops with a target
27389             {
27390               0f 84/jump-if-= break/disp32
27391               (emit-subx-cleanup-and-unconditional-nonlocal-branch *(ebp+8) %ecx *(ebp+0x10))
27392               e9/jump $emit-subx-stmt-list:clean-up/disp32
27393             }
27394           }
27395           # }}}
27396           # unconditional breaks {{{
27397           {
27398             # if (!string-equal?(curr-stmt->operation, "break")) break
27399             (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
27400             (string-equal? %eax "break")  # => eax
27401             3d/compare-eax-and 0/imm32/false
27402             0f 84/jump-if-= break/disp32
27403 $emit-subx-stmt-list:unconditional-break:
27404             81 7/subop/compare *(ecx+0xc) 0/imm32  # Stmt1-inouts
27405             # simple unconditional breaks without a target
27406             0f 84/jump-if-= $emit-subx-stmt-list:emit-cleanup/disp32  # easy: just skip remaining statements
27407             # unconditional breaks with a target
27408             (emit-subx-cleanup-and-unconditional-nonlocal-branch *(ebp+8) %ecx *(ebp+0x10))
27409             e9/jump $emit-subx-stmt-list:clean-up/disp32
27410           }
27411           # }}}
27412           # simple conditional branches without a target {{{
27413           81 7/subop/compare *(ecx+0xc) 0/imm32  # Stmt1-inouts
27414           {
27415             0f 85/jump-if-!= break/disp32
27416 $emit-subx-stmt-list:zero-arg-conditional-branch:
27417             # var old-block-depth/ebx: int = Curr-block-depth - 1
27418             8b/-> *Curr-block-depth 3/r32/ebx
27419             # cleanup prologue
27420             (emit-indent *(ebp+8) *Curr-block-depth)
27421             (write-buffered *(ebp+8) "{\n")
27422             ff 0/subop/increment *Curr-block-depth
27423             #
27424             (emit-reverse-break *(ebp+8) %ecx)
27425             # clean up until old block depth
27426             (emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) %ebx)
27427             # var target-block-depth/ebx: int = Curr-block-depth - 1
27428             4b/decrement-ebx
27429             # emit jump to target block
27430             (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
27431             (string-starts-with? %eax "break")  # => eax
27432             3d/compare-eax-and 0/imm32/false
27433             {
27434               74/jump-if-= break/disp8
27435               (emit-unconditional-jump-to-depth *(ebp+8) *(ebp+0x10) %ebx "break")
27436             }
27437             3d/compare-eax-and 0/imm32/false  # just in case the function call modified flags
27438             {
27439               75/jump-if-!= break/disp8
27440               (emit-unconditional-jump-to-depth *(ebp+8) *(ebp+0x10) %ebx "loop")
27441             }
27442             # cleanup epilogue
27443             ff 1/subop/decrement *Curr-block-depth
27444             (emit-indent *(ebp+8) *Curr-block-depth)
27445             (write-buffered *(ebp+8) "}\n")
27446             # continue
27447             e9/jump $emit-subx-stmt-list:continue/disp32
27448           }
27449           # }}}
27450           # conditional branches with an explicit target {{{
27451           {
27452             0f 84/jump-if-= break/disp32
27453 $emit-subx-stmt-list:conditional-branch-with-target:
27454             # cleanup prologue
27455             (emit-indent *(ebp+8) *Curr-block-depth)
27456             (write-buffered *(ebp+8) "{\n")
27457             ff 0/subop/increment *Curr-block-depth
27458             #
27459             (emit-reverse-break *(ebp+8) %ecx)
27460             (emit-subx-cleanup-and-unconditional-nonlocal-branch *(ebp+8) %ecx *(ebp+0x10))
27461             # cleanup epilogue
27462             ff 1/subop/decrement *Curr-block-depth
27463             (emit-indent *(ebp+8) *Curr-block-depth)
27464             (write-buffered *(ebp+8) "}\n")
27465             # continue
27466             e9/jump $emit-subx-stmt-list:continue/disp32
27467           }
27468           # }}}
27469         }
27470 $emit-subx-stmt-list:1-to-1:
27471         (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
27472         e9/jump $emit-subx-stmt-list:continue/disp32
27473       }
27474       {
27475 $emit-subx-stmt-list:check-for-var-def:
27476         81 7/subop/compare *ecx 2/imm32/var-def  # Stmt-tag
27477         75/jump-if-!= break/disp8
27478 $emit-subx-stmt-list:var-def:
27479         (emit-subx-var-def *(ebp+8) %ecx *(ebp+0x18) *(ebp+0x1c))
27480         (push *(ebp+0x10) *(ecx+4))  # Vardef-var
27481         (push *(ebp+0x10) *(ecx+8))  # Vardef-var
27482         (push *(ebp+0x10) 0)  # Live-var-register-spilled = 0 for vars on the stack
27483         #
27484         eb/jump $emit-subx-stmt-list:continue/disp8
27485       }
27486       {
27487 $emit-subx-stmt-list:check-for-reg-var-def:
27488         81 7/subop/compare *ecx 3/imm32/reg-var-def  # Stmt-tag
27489         0f 85/jump-if-!= break/disp32
27490 $emit-subx-stmt-list:reg-var-def:
27491         # TODO: ensure that there's exactly one output
27492         (push-output-and-maybe-emit-spill *(ebp+8) %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
27493         # emit the instruction as usual
27494         (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
27495         #
27496         eb/jump $emit-subx-stmt-list:continue/disp8
27497       }
27498 $emit-subx-stmt-list:continue:
27499       # TODO: raise an error on unrecognized Stmt-tag
27500       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
27501       89/<- %esi 0/r32/eax
27502       e9/jump loop/disp32
27503     }
27504 $emit-subx-stmt-list:emit-cleanup:
27505     (emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth)
27506 $emit-subx-stmt-list:clean-up:
27507     (clean-up-stack-offset-state *(ebp+0x10) *Curr-block-depth)
27508     (clean-up-blocks *(ebp+0x10) *Curr-block-depth *(ebp+0x14))
27509 $emit-subx-stmt-list:end:
27510     # . restore registers
27511     5e/pop-to-esi
27512     5b/pop-to-ebx
27513     59/pop-to-ecx
27514     58/pop-to-eax
27515     # . epilogue
27516     89/<- %esp 5/r32/ebp
27517     5d/pop-to-ebp
27518     c3/return
27520 # 'later-stmts' includes 'stmt', but will behave the same even without it; reg-var-def stmts are guaranteed not to write to function outputs.
27521 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)
27522     # . prologue
27523     55/push-ebp
27524     89/<- %ebp 4/r32/esp
27525     # . save registers
27526     50/push-eax
27527     51/push-ecx
27528     52/push-edx
27529     # ecx = stmt
27530     8b/-> *(ebp+0xc) 1/r32/ecx
27531     # var sv/eax: (addr stmt-var) = lookup(curr-stmt->outputs)
27532     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
27533     # TODO: assert !sv->is-deref?
27534     # var v/ecx: (addr var) = lookup(sv->value)
27535     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
27536     89/<- %ecx 0/r32/eax
27537     # v->block-depth = *Curr-block-depth
27538     8b/-> *Curr-block-depth 0/r32/eax
27539     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
27540 #?     (write-buffered Stderr "var ")
27541 #?     (lookup *ecx *(ecx+4))
27542 #?     (write-buffered Stderr %eax)
27543 #?     (write-buffered Stderr " at depth ")
27544 #?     (write-int32-hex-buffered Stderr *(ecx+0x10))
27545 #?     (write-buffered Stderr Newline)
27546 #?     (flush Stderr)
27547     # ensure that v is in a register
27548     81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
27549     0f 84/jump-if-= $push-output-and-maybe-emit-spill:abort/disp32
27550     # var emit-spill?/edx: boolean = not-yet-spilled-this-block? && will-not-write-some-register?(fn)
27551     (not-yet-spilled-this-block? %ecx *(ebp+0x10))  # => eax
27552     89/<- %edx 0/r32/eax
27553     3d/compare-eax-and 0/imm32/false
27554     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
27555     (will-not-write-some-register? %ecx *(ebp+0x14) *(ebp+0x18))  # => eax
27556     89/<- %edx 0/r32/eax
27557     # check emit-spill?
27558     3d/compare-eax-and 0/imm32/false
27559     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
27560     # TODO: assert(size-of(output) == 4)
27561     # *Curr-local-stack-offset -= 4
27562     81 5/subop/subtract *Curr-local-stack-offset 4/imm32
27563     # emit spill
27564     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
27565     (emit-push-register *(ebp+8) %eax)
27566 $push-output-and-maybe-emit-spill:push:
27567     8b/-> *(ebp+0xc) 1/r32/ecx
27568     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
27569     # push(vars, {sv->value, emit-spill?})
27570     (push *(ebp+0x10) *eax)  # Stmt-var-value
27571     (push *(ebp+0x10) *(eax+4))  # Stmt-var-value
27572     (push *(ebp+0x10) %edx)
27573 $push-output-and-maybe-emit-spill:end:
27574     # . restore registers
27575     5a/pop-to-edx
27576     59/pop-to-ecx
27577     58/pop-to-eax
27578     # . epilogue
27579     89/<- %esp 5/r32/ebp
27580     5d/pop-to-ebp
27581     c3/return
27583 $push-output-and-maybe-emit-spill:abort:
27584     # error("var '" var->name "' initialized from an instruction must live in a register\n")
27585     (write-buffered *(ebp+0x1c) "var '")
27586     (write-buffered *(ebp+0x1c) *eax)  # Var-name
27587     (write-buffered *(ebp+0x1c) "' initialized from an instruction must live in a register\n")
27588     (flush *(ebp+0x1c))
27589     (stop *(ebp+0x20) 1)
27590     # never gets here
27592 emit-subx-cleanup-and-unconditional-nonlocal-branch:  # out: (addr buffered-file), stmt: (addr stmt1), vars: (addr stack live-var)
27593     # . prologue
27594     55/push-ebp
27595     89/<- %ebp 4/r32/esp
27596     # . save registers
27597     50/push-eax
27598     51/push-ecx
27599     # ecx = stmt
27600     8b/-> *(ebp+0xc) 1/r32/ecx
27601     # var target/eax: (addr array byte) = curr-stmt->inouts->value->name
27602     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
27603     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
27604     (lookup *eax *(eax+4))  # Var-name Var-name => eax
27605     # clean up until target block
27606     (emit-cleanup-code-until-target *(ebp+8) *(ebp+0x10) %eax)
27607     # emit jump to target block
27608     (emit-indent *(ebp+8) *Curr-block-depth)
27609     (write-buffered *(ebp+8) "e9/jump ")
27610     (write-buffered *(ebp+8) %eax)
27611     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
27612     (string-starts-with? %eax "break")
27613     3d/compare-eax-and 0/imm32/false
27614     {
27615       74/jump-if-= break/disp8
27616       (write-buffered *(ebp+8) ":break/disp32\n")
27617       eb/jump $emit-subx-cleanup-and-unconditional-nonlocal-branch:end/disp8
27618     }
27619     (write-buffered *(ebp+8) ":loop/disp32\n")
27620 $emit-subx-cleanup-and-unconditional-nonlocal-branch:end:
27621     # . restore registers
27622     59/pop-to-ecx
27623     58/pop-to-eax
27624     # . epilogue
27625     89/<- %esp 5/r32/ebp
27626     5d/pop-to-ebp
27627     c3/return
27629 emit-outputs:  # out: (addr buffered-file), return-stmt: (addr stmt1), fn: (addr function)
27630     # . prologue
27631     55/push-ebp
27632     89/<- %ebp 4/r32/esp
27633     # . save registers
27634     50/push-eax
27635     51/push-ecx
27636     56/push-esi
27637     57/push-edi
27638     # var curr-inout/esi: (addr stmt-var) = return-stmt->inouts
27639     8b/-> *(ebp+0xc) 0/r32/eax
27640     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
27641     89/<- %esi 0/r32/eax
27642     # var curr-output/edi: (addr list var) = fn->outputs
27643     8b/-> *(ebp+0x10) 0/r32/eax
27644     (lookup *(eax+0x10) *(eax+0x14))  # Function-outputs Function-outputs => eax
27645     89/<- %edi 0/r32/eax
27646     {
27647 $emit-outputs:loop:
27648       81 7/subop/compare %esi 0/imm32
27649       0f 84/jump-if-= break/disp32
27650       # emit copy to output register
27651       # var curr-output-register/ecx: (addr array byte) = curr-output->value->register
27652       (lookup *edi *(edi+4))  # List-value List-value => eax
27653       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
27654       89/<- %ecx 0/r32/eax
27655       # if curr-output-register starts with "x", emit a floating-point copy
27656       8a/copy-byte *(ecx+4) 0/r32/AL
27657       25/and-eax-with 0xff/imm32
27658       3d/compare-eax-and 0x78/imm32/x
27659       {
27660         75/jump-if-!= break/disp8
27661         (emit-float-output *(ebp+8) %esi %ecx)
27662         eb/jump $emit-outputs:continue/disp8
27663       }
27664       # otherwise emit an int copy
27665       (emit-int-output *(ebp+8) %esi %ecx)
27666 $emit-outputs:continue:
27667       # curr-inout = curr-inout->next
27668       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
27669       89/<- %esi 0/r32/eax
27670       # curr-output = curr-output->next
27671       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
27672       89/<- %edi 0/r32/eax
27673       #
27674       e9/jump loop/disp32
27675     }
27676 $emit-outputs:end:
27677     # . restore registers
27678     5f/pop-to-edi
27679     5e/pop-to-esi
27680     59/pop-to-ecx
27681     58/pop-to-eax
27682     # . epilogue
27683     89/<- %esp 5/r32/ebp
27684     5d/pop-to-ebp
27685     c3/return
27687 emit-int-output:  # out: (addr buffered-file), return-var: (addr stmt-var), dest-reg: (addr array byte)
27688     # . prologue
27689     55/push-ebp
27690     89/<- %ebp 4/r32/esp
27691     # . save registers
27692     50/push-eax
27693     51/push-ecx
27694     # ecx = return-var->value
27695     8b/-> *(ebp+0xc) 0/r32/eax
27696     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
27697     89/<- %ecx 0/r32/eax
27698     # if curr-var is a literal, emit copy of a literal to the output
27699     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
27700     (simple-mu-type? %eax 0)  # literal => eax
27701     {
27702       3d/compare-eax-and 0/imm32/false
27703       0f 84/jump-if-= break/disp32
27704       (emit-indent *(ebp+8) *Curr-block-depth)
27705       (write-buffered *(ebp+8) "c7 0/subop/copy %")
27706       (write-buffered *(ebp+8) *(ebp+0x10))
27707       (write-buffered *(ebp+8) " ")
27708       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
27709       (write-buffered *(ebp+8) %eax)
27710       (write-buffered *(ebp+8) "/imm32\n")
27711       e9/jump $emit-int-output:end/disp32
27712     }
27713     # otherwise emit an integer copy
27714     (emit-indent *(ebp+8) *Curr-block-depth)
27715     (write-buffered *(ebp+8) "8b/->")
27716     (emit-subx-var-as-rm32 *(ebp+8) *(ebp+0xc))
27717     (write-buffered *(ebp+8) " ")
27718     (get Mu-registers *(ebp+0x10) 0xc "Mu-registers")  # => eax
27719     (write-int32-hex-buffered *(ebp+8) *eax)
27720     (write-buffered *(ebp+8) "/r32\n")
27721 $emit-int-output:end:
27722     # . restore registers
27723     59/pop-to-ecx
27724     58/pop-to-eax
27725     # . epilogue
27726     89/<- %esp 5/r32/ebp
27727     5d/pop-to-ebp
27728     c3/return
27730 emit-float-output:  # out: (addr buffered-file), return-var: (addr stmt-var), dest-reg: (addr array byte)
27731     # . prologue
27732     55/push-ebp
27733     89/<- %ebp 4/r32/esp
27734     # . save registers
27735     50/push-eax
27736     #
27737     (emit-indent *(ebp+8) *Curr-block-depth)
27738     (write-buffered *(ebp+8) "f3 0f 10/->")
27739     (emit-subx-var-as-rm32 *(ebp+8) *(ebp+0xc))
27740     (write-buffered *(ebp+8) " ")
27741     (get Mu-registers *(ebp+0x10) 0xc "Mu-registers")  # => eax
27742     (write-int32-hex-buffered *(ebp+8) *eax)
27743     (write-buffered *(ebp+8) "/x32\n")
27744 $emit-float-output:end:
27745     # . restore registers
27746     58/pop-to-eax
27747     # . epilogue
27748     89/<- %esp 5/r32/ebp
27749     5d/pop-to-ebp
27750     c3/return
27752 mu-branch?:  # stmt: (addr stmt1) -> result/eax: boolean
27753     # . prologue
27754     55/push-ebp
27755     89/<- %ebp 4/r32/esp
27756     # . save registers
27757     51/push-ecx
27758     # ecx = lookup(stmt->operation)
27759     8b/-> *(ebp+8) 1/r32/ecx
27760     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
27761     89/<- %ecx 0/r32/eax
27762     # if (stmt->operation starts with "loop") return true
27763     (string-starts-with? %ecx "loop")  # => eax
27764     3d/compare-eax-and 0/imm32/false
27765     75/jump-if-not-equal $mu-branch?:end/disp8
27766     # if (stmt->operation starts with "break") return true
27767     (string-starts-with? %ecx "break")  # => eax
27768     3d/compare-eax-and 0/imm32/false
27769     75/jump-if-not-equal $mu-branch?:end/disp8
27770     # otherwise return (stmt->operation starts with "return")
27771     (string-starts-with? %ecx "return")  # => eax
27772 $mu-branch?:end:
27773     # . restore registers
27774     59/pop-to-ecx
27775     # . epilogue
27776     89/<- %esp 5/r32/ebp
27777     5d/pop-to-ebp
27778     c3/return
27780 emit-reverse-break:  # out: (addr buffered-file), stmt: (addr stmt1)
27781     # . prologue
27782     55/push-ebp
27783     89/<- %ebp 4/r32/esp
27784     # . save registers
27785     50/push-eax
27786     # eax = stmt
27787     8b/-> *(ebp+0xc) 0/r32/eax
27788     #
27789     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
27790     (get Reverse-branch %eax 0x10 "reverse-branch: ")  # => eax: (addr handle array byte)
27791     (emit-indent *(ebp+8) *Curr-block-depth)
27792     (lookup *eax *(eax+4))  # => eax
27793     (write-buffered *(ebp+8) %eax)
27794     (write-buffered *(ebp+8) " break/disp32\n")
27795 $emit-reverse-break:end:
27796     # . restore registers
27797     58/pop-to-eax
27798     # . epilogue
27799     89/<- %esp 5/r32/ebp
27800     5d/pop-to-ebp
27801     c3/return
27803 == data
27805 # Table from Mu branch instructions to the reverse SubX opcodes for them.
27806 Reverse-branch:  # (table (handle array byte) (handle array byte))
27807   # a table is a stream
27808   0x240/imm32/write
27809   0/imm32/read
27810   0x240/imm32/size
27811   # data
27812   0x11/imm32/alloc-id   _string-break-if-=/imm32                0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
27813   0x11/imm32/alloc-id   _string-loop-if-=/imm32                 0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
27814   0x11/imm32/alloc-id   _string-break-if-!=/imm32               0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
27815   0x11/imm32/alloc-id   _string-loop-if-!=/imm32                0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
27816   0x11/imm32/alloc-id   _string-break-if-</imm32                0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
27817   0x11/imm32/alloc-id   _string-loop-if-</imm32                 0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
27818   0x11/imm32/alloc-id   _string-break-if->/imm32                0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
27819   0x11/imm32/alloc-id   _string-loop-if->/imm32                 0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
27820   0x11/imm32/alloc-id   _string-break-if-<=/imm32               0x11/imm32/alloc-id   _string_0f_8f_jump_label/imm32
27821   0x11/imm32/alloc-id   _string-loop-if-<=/imm32                0x11/imm32/alloc-id   _string_0f_8f_jump_label/imm32
27822   0x11/imm32/alloc-id   _string-break-if->=/imm32               0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
27823   0x11/imm32/alloc-id   _string-loop-if->=/imm32                0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
27824   0x11/imm32/alloc-id   _string-break-if-addr</imm32            0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
27825   0x11/imm32/alloc-id   _string-loop-if-addr</imm32             0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
27826   0x11/imm32/alloc-id   _string-break-if-addr>/imm32            0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
27827   0x11/imm32/alloc-id   _string-loop-if-addr>/imm32             0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
27828   0x11/imm32/alloc-id   _string-break-if-addr<=/imm32           0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
27829   0x11/imm32/alloc-id   _string-loop-if-addr<=/imm32            0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
27830   0x11/imm32/alloc-id   _string-break-if-addr>=/imm32           0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
27831   0x11/imm32/alloc-id   _string-loop-if-addr>=/imm32            0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
27832   0x11/imm32/alloc-id   _string-break-if-float</imm32           0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
27833   0x11/imm32/alloc-id   _string-loop-if-float</imm32            0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
27834   0x11/imm32/alloc-id   _string-break-if-float>/imm32           0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
27835   0x11/imm32/alloc-id   _string-loop-if-float>/imm32            0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
27836   0x11/imm32/alloc-id   _string-break-if-float<=/imm32          0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
27837   0x11/imm32/alloc-id   _string-loop-if-float<=/imm32           0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
27838   0x11/imm32/alloc-id   _string-break-if-float>=/imm32          0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
27839   0x11/imm32/alloc-id   _string-loop-if-float>=/imm32           0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
27840   0x11/imm32/alloc-id   _string-break-if-carry/imm32            0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
27841   0x11/imm32/alloc-id   _string-loop-if-carry/imm32             0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
27842   0x11/imm32/alloc-id   _string-break-if-not-carry/imm32        0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
27843   0x11/imm32/alloc-id   _string-loop-if-not-carry/imm32         0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
27844   0x11/imm32/alloc-id   _string-break-if-overflow/imm32         0x11/imm32/alloc-id   _string_0f_81_jump_label/imm32
27845   0x11/imm32/alloc-id   _string-loop-if-overflow/imm32          0x11/imm32/alloc-id   _string_0f_81_jump_label/imm32
27846   0x11/imm32/alloc-id   _string-break-if-not-overflow/imm32     0x11/imm32/alloc-id   _string_0f_80_jump_label/imm32
27847   0x11/imm32/alloc-id   _string-loop-if-not-overflow/imm32      0x11/imm32/alloc-id   _string_0f_80_jump_label/imm32
27849 == code
27851 emit-unconditional-jump-to-depth:  # out: (addr buffered-file), vars: (addr stack live-var), depth: int, label-suffix: (addr array byte)
27852     # . prologue
27853     55/push-ebp
27854     89/<- %ebp 4/r32/esp
27855     # . save registers
27856     50/push-eax
27857     51/push-ecx
27858     52/push-edx
27859     53/push-ebx
27860     56/push-esi
27861     # ecx = vars
27862     8b/-> *(ebp+0xc) 1/r32/ecx
27863     # var eax: int = vars->top
27864     8b/-> *ecx 0/r32/eax
27865     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
27866     8d/copy-address *(ecx+eax-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
27867     # var min/ecx: (addr handle var) = vars->data
27868     8d/copy-address *(ecx+8) 1/r32/ecx
27869     # edx = depth
27870     8b/-> *(ebp+0x10) 2/r32/edx
27871     {
27872 $emit-unconditional-jump-to-depth:loop:
27873       # if (curr < min) break
27874       39/compare %esi 1/r32/ecx
27875       0f 82/jump-if-addr< break/disp32
27876       # var v/ebx: (addr var) = lookup(*curr)
27877       (lookup *esi *(esi+4))  # => eax
27878       89/<- %ebx 0/r32/eax
27879       # if (v->block-depth < until-block-depth) break
27880       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
27881       0f 8c/jump-if-< break/disp32
27882       {
27883 $emit-unconditional-jump-to-depth:check:
27884         # if v->block-depth != until-block-depth, continue
27885         39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
27886         0f 85/jump-if-!= break/disp32
27887 $emit-unconditional-jump-to-depth:depth-found:
27888         # if v is not a literal, continue
27889         (size-of %ebx)  # => eax
27890         3d/compare-eax-and 0/imm32
27891         0f 85/jump-if-!= break/disp32
27892 $emit-unconditional-jump-to-depth:label-found:
27893         # emit unconditional jump, then return
27894         (emit-indent *(ebp+8) *Curr-block-depth)
27895         (write-buffered *(ebp+8) "e9/jump ")
27896         (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
27897         (write-buffered *(ebp+8) %eax)
27898         (write-buffered *(ebp+8) ":")
27899         (write-buffered *(ebp+8) *(ebp+0x14))
27900         (write-buffered *(ebp+8) "/disp32\n")
27901         eb/jump $emit-unconditional-jump-to-depth:end/disp8
27902       }
27903       # curr -= 12
27904       81 5/subop/subtract %esi 0xc/imm32
27905       e9/jump loop/disp32
27906     }
27907     # TODO: error if no label at 'depth' was found
27908 $emit-unconditional-jump-to-depth:end:
27909     # . restore registers
27910     5e/pop-to-esi
27911     5b/pop-to-ebx
27912     5a/pop-to-edx
27913     59/pop-to-ecx
27914     58/pop-to-eax
27915     # . epilogue
27916     89/<- %esp 5/r32/ebp
27917     5d/pop-to-ebp
27918     c3/return
27920 # emit clean-up code for 'vars' until some block depth
27921 # doesn't actually modify 'vars' so we need traverse manually inside the stack
27922 emit-cleanup-code-until-depth:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-depth: int
27923     # . prologue
27924     55/push-ebp
27925     89/<- %ebp 4/r32/esp
27926     # . save registers
27927     50/push-eax
27928     51/push-ecx
27929     52/push-edx
27930     53/push-ebx
27931     56/push-esi
27932 #?     (write-buffered Stderr "--- cleanup\n")
27933 #?     (flush Stderr)
27934     # ecx = vars
27935     8b/-> *(ebp+0xc) 1/r32/ecx
27936     # var esi: int = vars->top
27937     8b/-> *ecx 6/r32/esi
27938     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
27939     8d/copy-address *(ecx+esi-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
27940     # var min/ecx: (addr handle var) = vars->data
27941     81 0/subop/add %ecx 8/imm32
27942     # edx = until-block-depth
27943     8b/-> *(ebp+0x10) 2/r32/edx
27944     {
27945 $emit-cleanup-code-until-depth:loop:
27946       # if (curr < min) break
27947       39/compare %esi 1/r32/ecx
27948       0f 82/jump-if-addr< break/disp32
27949       # var v/ebx: (addr var) = lookup(*curr)
27950       (lookup *esi *(esi+4))  # => eax
27951       89/<- %ebx 0/r32/eax
27952 #?       (lookup *ebx *(ebx+4))  # Var-name
27953 #?       (write-buffered Stderr "var ")
27954 #?       (write-buffered Stderr %eax)
27955 #?       (write-buffered Stderr Newline)
27956 #?       (flush Stderr)
27957       # if (v->block-depth < until-block-depth) break
27958       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
27959       0f 8c/jump-if-< break/disp32
27960       # if v is in a register
27961       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
27962       {
27963         0f 84/jump-if-= break/disp32
27964         {
27965 $emit-cleanup-code-until-depth:check-for-previous-spill:
27966           8b/-> *(esi+8) 0/r32/eax  # Live-var-register-spilled
27967           3d/compare-eax-and 0/imm32/false
27968           74/jump-if-= break/disp8
27969 $emit-cleanup-code-until-depth:reclaim-var-in-register:
27970           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
27971           (emit-pop-register *(ebp+8) %eax)
27972         }
27973         eb/jump $emit-cleanup-code-until-depth:continue/disp8
27974       }
27975       # otherwise v is on the stack
27976       {
27977         75/jump-if-!= break/disp8
27978 $emit-cleanup-code-until-depth:var-on-stack:
27979         (size-of %ebx)  # => eax
27980         # don't emit code for labels
27981         3d/compare-eax-and 0/imm32
27982         74/jump-if-= break/disp8
27983 $emit-cleanup-code-until-depth:reclaim-var-on-stack:
27984         (emit-indent *(ebp+8) *Curr-block-depth)
27985         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
27986         (write-int32-hex-buffered *(ebp+8) %eax)
27987         (write-buffered *(ebp+8) "/imm32\n")
27988       }
27989 $emit-cleanup-code-until-depth:continue:
27990       # curr -= 12
27991       81 5/subop/subtract %esi 0xc/imm32
27992       e9/jump loop/disp32
27993     }
27994 $emit-cleanup-code-until-depth:end:
27995     # . restore registers
27996     5e/pop-to-esi
27997     5b/pop-to-ebx
27998     5a/pop-to-edx
27999     59/pop-to-ecx
28000     58/pop-to-eax
28001     # . epilogue
28002     89/<- %esp 5/r32/ebp
28003     5d/pop-to-ebp
28004     c3/return
28006 # emit clean-up code for 'vars' that don't conflict with output registers
28007 # doesn't actually modify 'vars' so we need traverse manually inside the stack
28008 emit-cleanup-code-for-non-outputs:  # out: (addr buffered-file), vars: (addr stack live-var), fn: (addr function)
28009     # . prologue
28010     55/push-ebp
28011     89/<- %ebp 4/r32/esp
28012     # . save registers
28013     50/push-eax
28014     51/push-ecx
28015     52/push-edx
28016     53/push-ebx
28017     56/push-esi
28018     57/push-edi
28019     # ecx = vars
28020     8b/-> *(ebp+0xc) 1/r32/ecx
28021     # var esi: int = vars->top
28022     8b/-> *ecx 6/r32/esi
28023     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
28024     8d/copy-address *(ecx+esi-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
28025     # var min/ecx: (addr handle var) = vars->data
28026     81 0/subop/add %ecx 8/imm32
28027     {
28028 $emit-cleanup-code-for-non-outputs:loop:
28029       # if (curr < min) break
28030       39/compare %esi 1/r32/ecx
28031       0f 82/jump-if-addr< break/disp32
28032       # var v/ebx: (addr var) = lookup(*curr)
28033       (lookup *esi *(esi+4))  # => eax
28034       89/<- %ebx 0/r32/eax
28035       # if v is in a register
28036       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
28037       {
28038         0f 84/jump-if-= break/disp32
28039         {
28040 $emit-cleanup-code-for-non-outputs:check-for-previous-spill:
28041           8b/-> *(esi+8) 0/r32/eax  # Live-var-register-spilled
28042           3d/compare-eax-and 0/imm32/false
28043           0f 84/jump-if-= break/disp32
28044 $emit-cleanup-code-for-non-outputs:reclaim-var-in-register:
28045           # var reg/edi: (addr array name) = v->register
28046           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
28047           89/<- %edi 0/r32/eax
28048           # if reg is not in function outputs, emit a pop
28049           (reg-in-function-outputs? *(ebp+0x10) %edi)  # => eax
28050           3d/compare-eax-and 0/imm32/false
28051           {
28052             75/jump-if-!= break/disp8
28053             (emit-pop-register *(ebp+8) %edi)
28054             eb/jump $emit-cleanup-code-for-non-outputs:reclaim-var-in-register-done/disp8
28055           }
28056           # otherwise just drop it from the stack
28057           (emit-indent *(ebp+8) *Curr-block-depth)
28058           (write-buffered *(ebp+8) "81 0/subop/add %esp 4/imm32\n")
28059         }
28060 $emit-cleanup-code-for-non-outputs:reclaim-var-in-register-done:
28061         eb/jump $emit-cleanup-code-for-non-outputs:continue/disp8
28062       }
28063       # otherwise v is on the stack
28064       {
28065         75/jump-if-!= break/disp8
28066 $emit-cleanup-code-for-non-outputs:var-on-stack:
28067         (size-of %ebx)  # => eax
28068         # don't emit code for labels
28069         3d/compare-eax-and 0/imm32
28070         74/jump-if-= break/disp8
28071 $emit-cleanup-code-for-non-outputs:reclaim-var-on-stack:
28072         (emit-indent *(ebp+8) *Curr-block-depth)
28073         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
28074         (write-int32-hex-buffered *(ebp+8) %eax)
28075         (write-buffered *(ebp+8) "/imm32\n")
28076       }
28077 $emit-cleanup-code-for-non-outputs:continue:
28078       # curr -= 12
28079       81 5/subop/subtract %esi 0xc/imm32
28080       e9/jump loop/disp32
28081     }
28082 $emit-cleanup-code-for-non-outputs:end:
28083     # . restore registers
28084     5f/pop-to-edi
28085     5e/pop-to-esi
28086     5b/pop-to-ebx
28087     5a/pop-to-edx
28088     59/pop-to-ecx
28089     58/pop-to-eax
28090     # . epilogue
28091     89/<- %esp 5/r32/ebp
28092     5d/pop-to-ebp
28093     c3/return
28095 emit-push-register:  # out: (addr buffered-file), reg: (addr array byte)
28096     # . prologue
28097     55/push-ebp
28098     89/<- %ebp 4/r32/esp
28099     # eax = reg
28100     8b/-> *(ebp+0xc) 0/r32/eax
28101     # var prefix/eax: byte = reg->data[0]
28102     8a/copy-byte *(eax+4) 0/r32/AL
28103     25/and-eax-with 0xff/imm32
28104     # if (prefix == 'x') push xmm register
28105     {
28106       3d/compare-eax-and 0x78/imm32/x
28107       0f 85/jump-if-!= break/disp32
28108       # TODO validate register
28109       (emit-indent *(ebp+8) *Curr-block-depth)
28110       (write-buffered *(ebp+8) "81 5/subop/subtract %esp 4/imm32\n")
28111       (emit-indent *(ebp+8) *Curr-block-depth)
28112       (write-buffered *(ebp+8) "f3 0f 11/<- *esp ")
28113       # var prefix/eax: byte = reg->data[3]
28114       8b/-> *(ebp+0xc) 0/r32/eax
28115       8a/copy-byte *(eax+7) 0/r32/AL
28116       25/and-eax-with 0xff/imm32
28117       (write-byte-buffered *(ebp+8) %eax)
28118       (write-buffered *(ebp+8) "/x32\n")
28119       e9/jump $emit-push-register:end/disp32
28120     }
28121     # otherwise push gp register
28122     (emit-indent *(ebp+8) *Curr-block-depth)
28123     (write-buffered *(ebp+8) "ff 6/subop/push %")
28124     (write-buffered *(ebp+8) *(ebp+0xc))
28125     (write-buffered *(ebp+8) Newline)
28126 $emit-push-register:end:
28127     # . epilogue
28128     89/<- %esp 5/r32/ebp
28129     5d/pop-to-ebp
28130     c3/return
28132 emit-pop-register:  # out: (addr buffered-file), reg: (addr array byte)
28133     # . prologue
28134     55/push-ebp
28135     89/<- %ebp 4/r32/esp
28136     # . save registers
28137     50/push-eax
28138     # eax = reg
28139     8b/-> *(ebp+0xc) 0/r32/eax
28140     # var prefix/eax: byte = reg->data[0]
28141     8a/copy-byte *(eax+4) 0/r32/AL
28142     25/and-eax-with 0xff/imm32
28143     # if (prefix == 'x') pop to xmm register
28144     {
28145       3d/compare-eax-and 0x78/imm32/x
28146       0f 85/jump-if-!= break/disp32
28147       # TODO validate register
28148       (emit-indent *(ebp+8) *Curr-block-depth)
28149       (write-buffered *(ebp+8) "f3 0f 10/-> *esp ")
28150       # var prefix/eax: byte = reg->data[3]
28151       8b/-> *(ebp+0xc) 0/r32/eax
28152       8a/copy-byte *(eax+7) 0/r32/AL
28153       25/and-eax-with 0xff/imm32
28154       (write-byte-buffered *(ebp+8) %eax)
28155       (write-buffered *(ebp+8) "/x32\n")
28156       (emit-indent *(ebp+8) *Curr-block-depth)
28157       (write-buffered *(ebp+8) "81 0/subop/add %esp 4/imm32\n")
28158       e9/jump $emit-pop-register:end/disp32
28159     }
28160     # otherwise pop to gp register
28161     (emit-indent *(ebp+8) *Curr-block-depth)
28162     (write-buffered *(ebp+8) "8f 0/subop/pop %")
28163     (write-buffered *(ebp+8) *(ebp+0xc))
28164     (write-buffered *(ebp+8) Newline)
28165 $emit-pop-register:end:
28166     # . restore registers
28167     58/pop-to-eax
28168     # . epilogue
28169     89/<- %esp 5/r32/ebp
28170     5d/pop-to-ebp
28171     c3/return
28173 # emit clean-up code for 'vars' until a given label is encountered
28174 # doesn't actually modify 'vars' so we need traverse manually inside the stack
28175 emit-cleanup-code-until-target:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-label: (addr array byte)
28176     # . prologue
28177     55/push-ebp
28178     89/<- %ebp 4/r32/esp
28179     # . save registers
28180     50/push-eax
28181     51/push-ecx
28182     52/push-edx
28183     53/push-ebx
28184     # ecx = vars
28185     8b/-> *(ebp+0xc) 1/r32/ecx
28186     # var eax: int = vars->top
28187     8b/-> *ecx 0/r32/eax
28188     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
28189     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
28190     # var min/ecx: (addr handle var) = vars->data
28191     81 0/subop/add %ecx 8/imm32
28192     {
28193 $emit-cleanup-code-until-target:loop:
28194       # if (curr < min) break
28195       39/compare %edx 1/r32/ecx
28196       0f 82/jump-if-addr< break/disp32
28197       # var v/ebx: (handle var) = lookup(*curr)
28198       (lookup *edx *(edx+4))  # => eax
28199       89/<- %ebx 0/r32/eax
28200       # if (v->name == until-block-label) break
28201       (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
28202       (string-equal? %eax *(ebp+0x10))  # => eax
28203       3d/compare-eax-and 0/imm32/false
28204       0f 85/jump-if-!= break/disp32
28205       # if v is in a register
28206       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
28207       {
28208         0f 84/jump-if-= break/disp32
28209         {
28210 $emit-cleanup-code-until-target:check-for-previous-spill:
28211           8b/-> *(edx+8) 0/r32/eax  # Live-var-register-spilled
28212           3d/compare-eax-and 0/imm32/false
28213           74/jump-if-= break/disp8
28214 $emit-cleanup-code-until-target:reclaim-var-in-register:
28215           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
28216           (emit-pop-register *(ebp+8) %eax)
28217         }
28218         eb/jump $emit-cleanup-code-until-target:continue/disp8
28219       }
28220       # otherwise v is on the stack
28221       {
28222         75/jump-if-!= break/disp8
28223 $emit-cleanup-code-until-target:reclaim-var-on-stack:
28224         (size-of %ebx)  # => eax
28225         # don't emit code for labels
28226         3d/compare-eax-and 0/imm32
28227         74/jump-if-= break/disp8
28228         #
28229         (emit-indent *(ebp+8) *Curr-block-depth)
28230         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
28231         (write-int32-hex-buffered *(ebp+8) %eax)
28232         (write-buffered *(ebp+8) "/imm32\n")
28233       }
28234 $emit-cleanup-code-until-target:continue:
28235       # curr -= 12
28236       81 5/subop/subtract %edx 0xc/imm32
28237       e9/jump loop/disp32
28238     }
28239 $emit-cleanup-code-until-target:end:
28240     # . restore registers
28241     5b/pop-to-ebx
28242     5a/pop-to-edx
28243     59/pop-to-ecx
28244     58/pop-to-eax
28245     # . epilogue
28246     89/<- %esp 5/r32/ebp
28247     5d/pop-to-ebp
28248     c3/return
28250 # update Curr-local-stack-offset assuming vars until some block depth are popped
28251 # doesn't actually modify 'vars', so we need traverse manually inside the stack
28252 clean-up-stack-offset-state:  # vars: (addr stack live-var), until-block-depth: int
28253     # . prologue
28254     55/push-ebp
28255     89/<- %ebp 4/r32/esp
28256     # . save registers
28257     50/push-eax
28258     51/push-ecx
28259     52/push-edx
28260     53/push-ebx
28261     56/push-esi
28262     # ecx = vars
28263     8b/-> *(ebp+8) 1/r32/ecx
28264     # var esi: int = vars->top
28265     8b/-> *ecx 6/r32/esi
28266     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
28267     8d/copy-address *(ecx+esi-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
28268     # var min/ecx: (addr handle var) = vars->data
28269     81 0/subop/add %ecx 8/imm32
28270     # edx = until-block-depth
28271     8b/-> *(ebp+0xc) 2/r32/edx
28272     {
28273 $clean-up-stack-offset-state:loop:
28274       # if (curr < min) break
28275       39/compare %esi 1/r32/ecx
28276       0f 82/jump-if-addr< break/disp32
28277       # var v/ebx: (addr var) = lookup(*curr)
28278       (lookup *esi *(esi+4))  # => eax
28279       89/<- %ebx 0/r32/eax
28280       # if (v->block-depth < until-block-depth) break
28281       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
28282       0f 8c/jump-if-< break/disp32
28283       # if v is in a register
28284       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
28285       {
28286         0f 84/jump-if-= break/disp32
28287         {
28288 $clean-up-stack-offset-state:check-for-previous-spill:
28289           8b/-> *(esi+8) 0/r32/eax  # Live-var-register-spilled
28290           3d/compare-eax-and 0/imm32/false
28291           74/jump-if-= break/disp8
28292 $clean-up-stack-offset-state:reclaim-var-in-register:
28293           81 0/subop/add *Curr-local-stack-offset 4/imm32
28294         }
28295         eb/jump $clean-up-stack-offset-state:continue/disp8
28296       }
28297       # otherwise v is on the stack
28298       {
28299         75/jump-if-!= break/disp8
28300 $clean-up-stack-offset-state:var-on-stack:
28301         (size-of %ebx)  # => eax
28302         01/add-to *Curr-local-stack-offset 0/r32/eax
28303       }
28304 $clean-up-stack-offset-state:continue:
28305       # curr -= 12
28306       81 5/subop/subtract %esi 0xc/imm32
28307       e9/jump loop/disp32
28308     }
28309 $clean-up-stack-offset-state:end:
28310     # . restore registers
28311     5e/pop-to-esi
28312     5b/pop-to-ebx
28313     5a/pop-to-edx
28314     59/pop-to-ecx
28315     58/pop-to-eax
28316     # . epilogue
28317     89/<- %esp 5/r32/ebp
28318     5d/pop-to-ebp
28319     c3/return
28321 # Return true if there isn't a variable in 'vars' with the same block-depth
28322 # and register as 'v'.
28323 # 'v' is guaranteed not to be within 'vars'.
28324 not-yet-spilled-this-block?:  # v: (addr var), vars: (addr stack live-var) -> result/eax: boolean
28325     # . prologue
28326     55/push-ebp
28327     89/<- %ebp 4/r32/esp
28328     # . save registers
28329     51/push-ecx
28330     52/push-edx
28331     53/push-ebx
28332     56/push-esi
28333     57/push-edi
28334     # ecx = vars
28335     8b/-> *(ebp+0xc) 1/r32/ecx
28336     # var eax: int = vars->top
28337     8b/-> *ecx 0/r32/eax
28338     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
28339     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
28340     # var min/ecx: (addr handle var) = vars->data
28341     8d/copy-address *(ecx+8) 1/r32/ecx
28342     # var depth/ebx: int = v->block-depth
28343     8b/-> *(ebp+8) 3/r32/ebx
28344     8b/-> *(ebx+0x10) 3/r32/ebx  # Var-block-depth
28345     # var needle/esi: (addr array byte) = v->register
28346     8b/-> *(ebp+8) 6/r32/esi
28347     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
28348     89/<- %esi 0/r32/eax
28349     {
28350 $not-yet-spilled-this-block?:loop:
28351       # if (curr < min) break
28352       39/compare %edx 1/r32/ecx
28353       0f 82/jump-if-addr< break/disp32
28354       # var cand/edi: (addr var) = lookup(*curr)
28355       (lookup *edx *(edx+4))  # => eax
28356       89/<- %edi 0/r32/eax
28357       # if (cand->block-depth < depth) break
28358       39/compare *(edi+0x10) 3/r32/ebx  # Var-block-depth
28359       0f 8c/jump-if-< break/disp32
28360       # var cand-reg/edi: (array array byte) = cand->reg
28361       (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
28362       89/<- %edi 0/r32/eax
28363       # if (cand-reg == null) continue
28364       {
28365 $not-yet-spilled-this-block?:check-reg:
28366         81 7/subop/compare %edi 0/imm32
28367         0f 84/jump-if-= break/disp32
28368         # if (cand-reg == needle) return true
28369         (string-equal? %esi %edi)  # => eax
28370         3d/compare-eax-and 0/imm32/false
28371         74/jump-if-= break/disp8
28372 $not-yet-spilled-this-block?:return-false:
28373         b8/copy-to-eax 0/imm32/false
28374         eb/jump $not-yet-spilled-this-block?:end/disp8
28375       }
28376 $not-yet-spilled-this-block?:continue:
28377       # curr -= 12
28378       81 5/subop/subtract %edx 0xc/imm32
28379       e9/jump loop/disp32
28380     }
28381 $not-yet-spilled-this-block?:return-true:
28382     # return true
28383     b8/copy-to-eax 1/imm32/true
28384 $not-yet-spilled-this-block?:end:
28385     # . restore registers
28386     5f/pop-to-edi
28387     5e/pop-to-esi
28388     5b/pop-to-ebx
28389     5a/pop-to-edx
28390     59/pop-to-ecx
28391     # . epilogue
28392     89/<- %esp 5/r32/ebp
28393     5d/pop-to-ebp
28394     c3/return
28396 # could the register of 'v' ever be written to by one of the vars in fn-outputs?
28397 will-not-write-some-register?:  # v: (addr var), stmts: (addr list stmt), fn: (addr function) -> result/eax: boolean
28398     # . prologue
28399     55/push-ebp
28400     89/<- %ebp 4/r32/esp
28401     # eax = v
28402     8b/-> *(ebp+8) 0/r32/eax
28403     # var reg/eax: (addr array byte) = lookup(v->register)
28404     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
28405     # var target/eax: (addr var) = find-register(fn-outputs, reg)
28406     (find-register *(ebp+0x10) %eax)  # => eax
28407     # if (target == 0) return true
28408     {
28409       3d/compare-eax-and 0/imm32
28410       75/jump-if-!= break/disp8
28411       b8/copy-to-eax 1/imm32/true
28412       eb/jump $will-not-write-some-register?:end/disp8
28413     }
28414     # return !assigns-in-stmts?(stmts, target)
28415     (assigns-in-stmts? *(ebp+0xc) %eax)  # => eax
28416     3d/compare-eax-and 0/imm32/false
28417     # assume: true = 1, so no need to mask with 0x000000ff
28418     0f 94/set-if-= %al
28419 $will-not-write-some-register?:end:
28420     # . epilogue
28421     89/<- %esp 5/r32/ebp
28422     5d/pop-to-ebp
28423     c3/return
28425 # return fn output with matching register
28426 # always returns false if 'reg' is null
28427 find-register:  # fn: (addr function), reg: (addr array byte) -> result/eax: (addr var)
28428     # . prologue
28429     55/push-ebp
28430     89/<- %ebp 4/r32/esp
28431     # . save registers
28432     51/push-ecx
28433     # var curr/ecx: (addr list var) = lookup(fn->outputs)
28434     8b/-> *(ebp+8) 1/r32/ecx
28435     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
28436     89/<- %ecx 0/r32/eax
28437     {
28438 $find-register:loop:
28439       # if (curr == 0) break
28440       81 7/subop/compare %ecx 0/imm32
28441       74/jump-if-= break/disp8
28442       # eax = curr->value->register
28443       (lookup *ecx *(ecx+4))  # List-value List-value => eax
28444       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
28445       # if (eax == reg) return curr->value
28446 $find-register:compare:
28447       (string-equal? *(ebp+0xc) %eax)  # => eax
28448       {
28449         3d/compare-eax-and 0/imm32/false
28450         74/jump-if-= break/disp8
28451 $find-register:found:
28452         (lookup *ecx *(ecx+4))  # List-value List-value => eax
28453         eb/jump $find-register:end/disp8
28454       }
28455       # curr = lookup(curr->next)
28456       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
28457       89/<- %ecx 0/r32/eax
28458       #
28459       eb/jump loop/disp8
28460     }
28461 $find-register:end:
28462     # . restore registers
28463     59/pop-to-ecx
28464     # . epilogue
28465     89/<- %esp 5/r32/ebp
28466     5d/pop-to-ebp
28467     c3/return
28469 assigns-in-stmts?:  # stmts: (addr list stmt), v: (addr var) -> result/eax: boolean
28470     # . prologue
28471     55/push-ebp
28472     89/<- %ebp 4/r32/esp
28473     # . save registers
28474     51/push-ecx
28475     # var curr/ecx: (addr list stmt) = stmts
28476     8b/-> *(ebp+8) 1/r32/ecx
28477     {
28478       # if (curr == 0) break
28479       81 7/subop/compare %ecx 0/imm32
28480       74/jump-if-= break/disp8
28481       # if assigns-in-stmt?(curr->value, v) return true
28482       (lookup *ecx *(ecx+4))  # List-value List-value => eax
28483       (assigns-in-stmt? %eax *(ebp+0xc))  # => eax
28484       3d/compare-eax-and 0/imm32/false
28485       75/jump-if-!= break/disp8
28486       # curr = lookup(curr->next)
28487       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
28488       89/<- %ecx 0/r32/eax
28489       #
28490       eb/jump loop/disp8
28491     }
28492 $assigns-in-stmts?:end:
28493     # . restore registers
28494     59/pop-to-ecx
28495     # . epilogue
28496     89/<- %esp 5/r32/ebp
28497     5d/pop-to-ebp
28498     c3/return
28500 assigns-in-stmt?:  # stmt: (addr stmt), v: (addr var) -> result/eax: boolean
28501     # . prologue
28502     55/push-ebp
28503     89/<- %ebp 4/r32/esp
28504     # . save registers
28505     51/push-ecx
28506     # ecx = stmt
28507     8b/-> *(ebp+8) 1/r32/ecx
28508     # if stmt is a stmt1, return assigns-in-stmt-vars?(stmt->outputs, v)
28509     {
28510       81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
28511       75/jump-if-!= break/disp8
28512       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
28513       (assigns-in-stmt-vars? %eax *(ebp+0xc))  # => eax
28514       eb/jump $assigns-in-stmt?:end/disp8
28515     }
28516     # if stmt is a block, return assigns-in-stmts?(stmt->stmts, v)
28517     {
28518       81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
28519       75/jump-if-!= break/disp8
28520       (lookup *(ecx+4) *(ecx+8))  # Block-stmts Block-stmts => eax
28521       (assigns-in-stmts? %eax *(ebp+0xc))  # => eax
28522       eb/jump $assigns-in-stmt?:end/disp8
28523     }
28524     # otherwise return false
28525     b8/copy 0/imm32/false
28526 $assigns-in-stmt?:end:
28527     # . restore registers
28528     59/pop-to-ecx
28529     # . epilogue
28530     89/<- %esp 5/r32/ebp
28531     5d/pop-to-ebp
28532     c3/return
28534 assigns-in-stmt-vars?:  # stmt-var: (addr stmt-var), v: (addr var) -> result/eax: boolean
28535     # . prologue
28536     55/push-ebp
28537     89/<- %ebp 4/r32/esp
28538     # . save registers
28539     51/push-ecx
28540     # var curr/ecx: (addr stmt-var) = stmt-var
28541     8b/-> *(ebp+8) 1/r32/ecx
28542     {
28543       # if (curr == 0) break
28544       81 7/subop/compare %ecx 0/imm32
28545       74/jump-if-= break/disp8
28546       # eax = lookup(curr->value)
28547       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
28548       # if (eax == v  &&  curr->is-deref? == false) return true
28549       {
28550         39/compare *(ebp+0xc) 0/r32/eax
28551         75/jump-if-!= break/disp8
28552         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
28553         75/jump-if-!= break/disp8
28554         b8/copy-to-eax 1/imm32/true
28555         eb/jump $assigns-in-stmt-vars?:end/disp8
28556       }
28557       # curr = lookup(curr->next)
28558       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
28559       89/<- %ecx 0/r32/eax
28560       #
28561       eb/jump loop/disp8
28562     }
28563 $assigns-in-stmt-vars?:end:
28564     # . restore registers
28565     59/pop-to-ecx
28566     # . epilogue
28567     89/<- %esp 5/r32/ebp
28568     5d/pop-to-ebp
28569     c3/return
28571 # is there a var before 'v' with the same block-depth and register on the 'vars' stack?
28572 # v is guaranteed to be within vars
28573 # 'start' is provided as an optimization, a pointer within vars
28574 # *start == v
28575 same-register-spilled-before?:  # v: (addr var), vars: (addr stack (handle var)), start: (addr var) -> result/eax: boolean
28576     # . prologue
28577     55/push-ebp
28578     89/<- %ebp 4/r32/esp
28579     # . save registers
28580     51/push-ecx
28581     52/push-edx
28582     53/push-ebx
28583     56/push-esi
28584     57/push-edi
28585     # ecx = v
28586     8b/-> *(ebp+8) 1/r32/ecx
28587     # var reg/edx: (addr array byte) = lookup(v->register)
28588     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
28589     89/<- %edx 0/r32/eax
28590     # var depth/ebx: int = v->block-depth
28591     8b/-> *(ecx+0x10) 3/r32/ebx  # Var-block-depth
28592     # var min/ecx: (addr handle var) = vars->data
28593     8b/-> *(ebp+0xc) 1/r32/ecx
28594     81 0/subop/add %ecx 8/imm32
28595     # TODO: check that start >= min and start < &vars->data[top]
28596     # TODO: check that *start == v
28597     # var curr/esi: (addr handle var) = start
28598     8b/-> *(ebp+0x10) 6/r32/esi
28599     # curr -= 8
28600     81 5/subop/subtract %esi 8/imm32
28601     {
28602 $same-register-spilled-before?:loop:
28603       # if (curr < min) break
28604       39/compare %esi 1/r32/ecx
28605       0f 82/jump-if-addr< break/disp32
28606       # var x/eax: (addr var) = lookup(*curr)
28607       (lookup *esi *(esi+4))  # => eax
28608       # if (x->block-depth < depth) break
28609       39/compare *(eax+0x10) 3/r32/ebx  # Var-block-depth
28610       0f 8c/jump-if-< break/disp32
28611       # if (x->register == 0) continue
28612       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
28613       74/jump-if-= $same-register-spilled-before?:continue/disp8
28614       # if (x->register == reg) return true
28615       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
28616       (string-equal? %eax %edx)  # => eax
28617       3d/compare-eax-and 0/imm32/false
28618       b8/copy-to-eax 1/imm32/true
28619       75/jump-if-!= $same-register-spilled-before?:end/disp8
28620 $same-register-spilled-before?:continue:
28621       # curr -= 8
28622       81 5/subop/subtract %esi 8/imm32
28623       e9/jump loop/disp32
28624     }
28625 $same-register-spilled-before?:false:
28626     b8/copy-to-eax 0/imm32/false
28627 $same-register-spilled-before?:end:
28628     # . restore registers
28629     5f/pop-to-edi
28630     5e/pop-to-esi
28631     5b/pop-to-ebx
28632     5a/pop-to-edx
28633     59/pop-to-ecx
28634     # . epilogue
28635     89/<- %esp 5/r32/ebp
28636     5d/pop-to-ebp
28637     c3/return
28639 # clean up global state for 'vars' until some block depth (inclusive)
28640 clean-up-blocks:  # vars: (addr stack live-var), until-block-depth: int, fn: (addr function)
28641     # . prologue
28642     55/push-ebp
28643     89/<- %ebp 4/r32/esp
28644     # . save registers
28645     50/push-eax
28646     51/push-ecx
28647     56/push-esi
28648     # esi = vars
28649     8b/-> *(ebp+8) 6/r32/esi
28650     # ecx = until-block-depth
28651     8b/-> *(ebp+0xc) 1/r32/ecx
28652     {
28653 $clean-up-blocks:reclaim-loop:
28654       # if (vars->top <= 0) break
28655       8b/-> *esi 0/r32/eax  # Stack-top
28656       3d/compare-eax-and 0/imm32
28657       0f 8e/jump-if-<= break/disp32
28658       # var v/eax: (addr var) = lookup(vars[vars->top-12])
28659       (lookup *(esi+eax-4) *(esi+eax))  # vars + 8 + vars->top - 12 => eax
28660       # if (v->block-depth < until-block-depth) break
28661       39/compare *(eax+0x10) 1/r32/ecx  # Var-block-depth
28662       0f 8c/jump-if-< break/disp32
28663       (pop %esi)  # => eax
28664       (pop %esi)  # => eax
28665       (pop %esi)  # => eax
28666       e9/jump loop/disp32
28667     }
28668 $clean-up-blocks:end:
28669     # . restore registers
28670     5e/pop-to-esi
28671     59/pop-to-ecx
28672     58/pop-to-eax
28673     # . epilogue
28674     89/<- %esp 5/r32/ebp
28675     5d/pop-to-ebp
28676     c3/return
28678 reg-in-function-outputs?:  # fn: (addr function), target: (addr array byte) -> result/eax: boolean
28679     # . prologue
28680     55/push-ebp
28681     89/<- %ebp 4/r32/esp
28682     # . save registers
28683     51/push-ecx
28684     # var curr/ecx: (addr list var) = lookup(fn->outputs)
28685     8b/-> *(ebp+8) 0/r32/eax
28686     (lookup *(eax+0x10) *(eax+0x14))  # Function-outputs Function-outputs => eax
28687     89/<- %ecx 0/r32/eax
28688     # while curr != null
28689     {
28690       81 7/subop/compare %ecx 0/imm32
28691       74/jump-if-= break/disp8
28692       # var v/eax: (addr var) = lookup(curr->value)
28693       (lookup *ecx *(ecx+4))  # List-value List-value => eax
28694       # var reg/eax: (addr array byte) = lookup(v->register)
28695       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
28696       # if (reg == target) return true
28697       (string-equal? %eax *(ebp+0xc))  # => eax
28698       3d/compare-eax-and 0/imm32/false
28699       75/jump-if-!= $reg-in-function-outputs?:end/disp8
28700       # curr = curr->next
28701       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
28702       89/<- %ecx 0/r32/eax
28703       #
28704       eb/jump loop/disp8
28705     }
28706     # return false
28707     b8/copy-to-eax 0/imm32
28708 $reg-in-function-outputs?:end:
28709     # . restore registers
28710     59/pop-to-ecx
28711     # . epilogue
28712     89/<- %esp 5/r32/ebp
28713     5d/pop-to-ebp
28714     c3/return
28716 emit-subx-var-def:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
28717     # . prologue
28718     55/push-ebp
28719     89/<- %ebp 4/r32/esp
28720     # . save registers
28721     50/push-eax
28722     51/push-ecx
28723     52/push-edx
28724     # eax = stmt
28725     8b/-> *(ebp+0xc) 0/r32/eax
28726     # var v/ecx: (addr var)
28727     (lookup *(eax+4) *(eax+8))  # Vardef-var Vardef-var => eax
28728     89/<- %ecx 0/r32/eax
28729     # v->block-depth = *Curr-block-depth
28730     8b/-> *Curr-block-depth 0/r32/eax
28731     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
28732     # var n/edx: int = size-of(stmt->var)
28733     (size-of %ecx)  # => eax
28734     89/<- %edx 0/r32/eax
28735     # *Curr-local-stack-offset -= n
28736     29/subtract-from *Curr-local-stack-offset 2/r32/edx
28737     # v->offset = *Curr-local-stack-offset
28738     8b/-> *Curr-local-stack-offset 0/r32/eax
28739     89/<- *(ecx+0x14) 0/r32/eax  # Var-offset
28740     # if v is an array, do something special to initialize it
28741     {
28742       (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
28743       (mu-array? %eax)  # => eax
28744       3d/compare-eax-and 0/imm32/false
28745       0f 84/jump-if-= break/disp32
28746       # var array-size-without-size/edx: int = n-4
28747       81 5/subop/subtract %edx 4/imm32
28748       #
28749       (emit-array-data-initialization *(ebp+8) %edx)
28750       e9/jump $emit-subx-var-def:end/disp32
28751     }
28752     # another special-case for initializing streams
28753     # a stream is an array with 2 extra pointers
28754     {
28755       (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
28756       (mu-stream? %eax)  # => eax
28757       3d/compare-eax-and 0/imm32/false
28758       0f 84/jump-if-= break/disp32
28759       # var array-size-without-size/edx: int = n-12
28760       81 5/subop/subtract %edx 0xc/imm32
28761       (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
28762       (emit-stream-data-initialization *(ebp+8) %edx %eax *(ebp+0x10) *(ebp+0x14))
28763       # emit read and write pointers
28764       (emit-indent *(ebp+8) *Curr-block-depth)
28765       (write-buffered *(ebp+8) "68/push 0/imm32\n")
28766       (emit-indent *(ebp+8) *Curr-block-depth)
28767       (write-buffered *(ebp+8) "68/push 0/imm32\n")
28768       #
28769       eb/jump $emit-subx-var-def:end/disp8
28770     }
28771     # while n > 0
28772     {
28773       81 7/subop/compare %edx 0/imm32
28774       7e/jump-if-<= break/disp8
28775       (emit-indent *(ebp+8) *Curr-block-depth)
28776       (write-buffered *(ebp+8) "68/push 0/imm32\n")
28777       # n -= 4
28778       81 5/subop/subtract %edx 4/imm32
28779       #
28780       eb/jump loop/disp8
28781     }
28782 $emit-subx-var-def:end:
28783     # . restore registers
28784     5a/pop-to-edx
28785     59/pop-to-ecx
28786     58/pop-to-eax
28787     # . epilogue
28788     89/<- %esp 5/r32/ebp
28789     5d/pop-to-ebp
28790     c3/return
28792 emit-array-data-initialization:  # out: (addr buffered-file), n: int
28793     # . prologue
28794     55/push-ebp
28795     89/<- %ebp 4/r32/esp
28796     #
28797     (emit-indent *(ebp+8) *Curr-block-depth)
28798     (write-buffered *(ebp+8) "(push-n-zero-bytes ")
28799     (write-int32-hex-buffered *(ebp+8) *(ebp+0xc))
28800     (write-buffered *(ebp+8) ")\n")
28801     (emit-indent *(ebp+8) *Curr-block-depth)
28802     (write-buffered *(ebp+8) "68/push ")
28803     (write-int32-hex-buffered *(ebp+8) *(ebp+0xc))
28804     (write-buffered *(ebp+8) "/imm32\n")
28805 $emit-array-data-initialization:end:
28806     # . epilogue
28807     89/<- %esp 5/r32/ebp
28808     5d/pop-to-ebp
28809     c3/return
28811 emit-stream-data-initialization:  # out: (addr buffered-file), n: int, type: (addr type-tree), err: (addr buffered-file), ed: (addr exit-descriptor)
28812     # . prologue
28813     55/push-ebp
28814     89/<- %ebp 4/r32/esp
28815     # . save registers
28816     50/push-eax
28817     # Optimization: if it's a stream of bytes, don't initialize.
28818     #
28819     # We often construct large temporary streams on the stack for 'trace'
28820     # statements. Initializing such streams can significantly slow programs
28821     # down.
28822     #
28823     # Mu doesn't really depend on initializing stream contents for type- or
28824     # memory-safety; we're mostly doing so to make it easy to debug unsafe
28825     # SubX code that misuses stream objects by manipulating read/write
28826     # pointers. But you can't _really_ protect from unsafe SubX, so I think we
28827     # don't give up much safety or security here.
28828     {
28829       (stream-element-type-id *(ebp+0x10) *(ebp+0x14) *(ebp+0x18))  # => eax
28830       3d/compare-eax-and 8/imm32/byte
28831       75/jump-if-!= break/disp8
28832       (emit-indent *(ebp+8) *Curr-block-depth)
28833       (write-buffered *(ebp+8) "81 5/subop/subtract %esp ")
28834       (write-int32-hex-buffered *(ebp+8) *(ebp+0xc))
28835       (write-buffered *(ebp+8) "/imm32\n")
28836       eb/jump $emit-stream-data-initialization:emit-length/disp8
28837     }
28838     (emit-indent *(ebp+8) *Curr-block-depth)
28839     (write-buffered *(ebp+8) "(push-n-zero-bytes ")
28840     (write-int32-hex-buffered *(ebp+8) *(ebp+0xc))
28841     (write-buffered *(ebp+8) ")\n")
28842 $emit-stream-data-initialization:emit-length:
28843     (emit-indent *(ebp+8) *Curr-block-depth)
28844     (write-buffered *(ebp+8) "68/push ")
28845     (write-int32-hex-buffered *(ebp+8) *(ebp+0xc))
28846     (write-buffered *(ebp+8) "/imm32\n")
28847 $emit-stream-data-initialization:end:
28848     # . restore registers
28849     58/pop-to-eax
28850     # . epilogue
28851     89/<- %esp 5/r32/ebp
28852     5d/pop-to-ebp
28853     c3/return
28855 emit-subx-stmt:  # out: (addr buffered-file), stmt: (addr stmt), primitives: (addr primitive), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
28856     # . prologue
28857     55/push-ebp
28858     89/<- %ebp 4/r32/esp
28859     # . save registers
28860     50/push-eax
28861     51/push-ecx
28862     # - some special-case primitives that don't actually use the 'primitives' data structure
28863     # var op/ecx: (addr array byte) = lookup(stmt->operation)
28864     8b/-> *(ebp+0xc) 1/r32/ecx
28865     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
28866     89/<- %ecx 0/r32/eax
28867     # copy byte (can be a primitive except we need to emit a second instruction)
28868     {
28869       # if (!string-equal?(stmt->operation, "copy-byte")) break
28870       (string-equal? %ecx "copy-byte")  # => eax
28871       3d/compare-eax-and 0/imm32/false
28872       0f 84/jump-if-= break/disp32
28873       (translate-mu-copy-byte-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c))
28874       e9/jump $emit-subx-stmt:end/disp32
28875     }
28876     # copy-byte-to can be a primitive; writes to memory don't need to clear surrounding bytes
28877     # array size
28878     {
28879       # if (!string-equal?(stmt->operation, "length")) break
28880       (string-equal? %ecx "length")  # => eax
28881       3d/compare-eax-and 0/imm32/false
28882       0f 84/jump-if-= break/disp32
28883       (translate-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c))
28884       e9/jump $emit-subx-stmt:end/disp32
28885     }
28886     # index into array
28887     {
28888       # if (!string-equal?(stmt->operation, "index")) break
28889       (string-equal? %ecx "index")  # => eax
28890       3d/compare-eax-and 0/imm32/false
28891       0f 84/jump-if-= break/disp32
28892       (translate-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
28893       e9/jump $emit-subx-stmt:end/disp32
28894     }
28895     # compute-offset for index into array
28896     {
28897       # if (!string-equal?(stmt->operation, "compute-offset")) break
28898       (string-equal? %ecx "compute-offset")  # => eax
28899       3d/compare-eax-and 0/imm32/false
28900       0f 84/jump-if-= break/disp32
28901       (translate-mu-compute-offset-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c))
28902       e9/jump $emit-subx-stmt:end/disp32
28903     }
28904     # get field from record
28905     {
28906       # if (!string-equal?(stmt->operation, "get")) break
28907       (string-equal? %ecx "get")  # => eax
28908       3d/compare-eax-and 0/imm32/false
28909       0f 84/jump-if-= break/disp32
28910       (translate-mu-get-stmt *(ebp+8) *(ebp+0xc))
28911       e9/jump $emit-subx-stmt:end/disp32
28912     }
28913     # allocate scalar
28914     {
28915       # if (!string-equal?(stmt->operation, "allocate")) break
28916       (string-equal? %ecx "allocate")  # => eax
28917       3d/compare-eax-and 0/imm32/false
28918       0f 84/jump-if-= break/disp32
28919       (translate-mu-allocate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c))
28920       e9/jump $emit-subx-stmt:end/disp32
28921     }
28922     # copy-object
28923     {
28924       # if (!string-equal?(stmt->operation, "copy-object")) break
28925       (string-equal? %ecx "copy-object")  # => eax
28926       3d/compare-eax-and 0/imm32/false
28927       0f 84/jump-if-= break/disp32
28928       (translate-mu-copy-object-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c))
28929       e9/jump $emit-subx-stmt:end/disp32
28930     }
28931     # clear-object
28932     {
28933       # if (!string-equal?(stmt->operation, "clear-object")) break
28934       (string-equal? %ecx "clear-object")  # => eax
28935       3d/compare-eax-and 0/imm32/false
28936       0f 84/jump-if-= break/disp32
28937       (translate-mu-clear-object-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c))
28938       e9/jump $emit-subx-stmt:end/disp32
28939     }
28940     # allocate array
28941     {
28942       # if (!string-equal?(stmt->operation, "populate")) break
28943       (string-equal? %ecx "populate")  # => eax
28944       3d/compare-eax-and 0/imm32/false
28945       0f 84/jump-if-= break/disp32
28946       (translate-mu-populate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c))
28947       e9/jump $emit-subx-stmt:end/disp32
28948     }
28949     # allocate stream
28950     {
28951       # if (!string-equal?(stmt->operation, "populate-stream")) break
28952       (string-equal? %ecx "populate-stream")  # => eax
28953       3d/compare-eax-and 0/imm32/false
28954       0f 84/jump-if-= break/disp32
28955       (translate-mu-populate-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c))
28956       e9/jump $emit-subx-stmt:end/disp32
28957     }
28958     # read from stream
28959     {
28960       # if (!string-equal?(stmt->operation, "read-from-stream")) break
28961       (string-equal? %ecx "read-from-stream")  # => eax
28962       3d/compare-eax-and 0/imm32/false
28963       0f 84/jump-if-= break/disp32
28964       (translate-mu-read-from-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c))
28965       e9/jump $emit-subx-stmt:end/disp32
28966     }
28967     # write to stream
28968     {
28969       # if (!string-equal?(stmt->operation, "write-to-stream")) break
28970       (string-equal? %ecx "write-to-stream")  # => eax
28971       3d/compare-eax-and 0/imm32/false
28972       0f 84/jump-if-= break/disp32
28973       (translate-mu-write-to-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c))
28974       e9/jump $emit-subx-stmt:end/disp32
28975     }
28976     # - optimizations
28977     # if copy instruction has same register in source and destination, emit nothing
28978     (redundant-copy? *(ebp+0xc))  # => eax
28979     3d/compare-eax-and 0/imm32/false
28980     75/jump-if-!= $emit-subx-stmt:end/disp8
28981     # - if stmt matches a primitive, emit it
28982     {
28983 $emit-subx-stmt:check-for-primitive:
28984       # var curr/eax: (addr primitive)
28985       (find-matching-primitive *(ebp+0x10) *(ebp+0xc))  # primitives, stmt => eax
28986       3d/compare-eax-and 0/imm32
28987       74/jump-if-= break/disp8
28988 $emit-subx-stmt:primitive:
28989       (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax)  # out, stmt, curr
28990       e9/jump $emit-subx-stmt:end/disp32
28991     }
28992     # - otherwise emit a call
28993 $emit-subx-stmt:call:
28994     (emit-call *(ebp+8) *(ebp+0xc))
28995 $emit-subx-stmt:end:
28996     # . restore registers
28997     59/pop-to-ecx
28998     58/pop-to-eax
28999     # . epilogue
29000     89/<- %esp 5/r32/ebp
29001     5d/pop-to-ebp
29002     c3/return
29004 redundant-copy?:  # stmt: (addr stmt) -> result/eax: boolean
29005     # . prologue
29006     55/push-ebp
29007     89/<- %ebp 4/r32/esp
29008     # . save registers
29009     56/push-esi
29010     57/push-edi
29011     # esi = stmt
29012     8b/-> *(ebp+8) 6/r32/esi
29013     # if stmt->operation != "copy" return false
29014     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
29015     (string-equal? %eax "copy")  # => eax
29016     3d/compare-eax-and 0/imm32/false
29017     0f 84/jump-if-= $redundant-copy?:end/disp32
29018     # var output-reg/edi: (addr stmt-var) = stmt->outputs->value->register
29019     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
29020     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
29021     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
29022     # . if output-reg == null, return false
29023     3d/compare-eax-and 0/imm32
29024     74/jump-if-= $redundant-copy?:end/disp8
29025     89/<- %edi 0/r32/eax
29026     # return (inout->value->register == output->value->register)
29027     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
29028     # . if inout->is-deref return false
29029     81 7/subop/compare *(eax+0x10) 0/imm32/false  # Stmt-var-is-deref
29030     {
29031       74/jump-if-= break/disp8
29032       b8/copy-to-eax 0/imm32/false
29033       e9/jump $redundant-copy?:end/disp32
29034     }
29035     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
29036     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
29037     # . if inout-reg == null, return false
29038     3d/compare-eax-and 0/imm32
29039     74/jump-if-= $redundant-copy?:end/disp8
29040     (string-equal? %eax %edi)  # => eax
29041 $redundant-copy?:end:
29042     # . restore registers
29043     5f/pop-to-edi
29044     5e/pop-to-esi
29045     # . epilogue
29046     89/<- %esp 5/r32/ebp
29047     5d/pop-to-ebp
29048     c3/return
29050 translate-mu-length-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
29051     # . prologue
29052     55/push-ebp
29053     89/<- %ebp 4/r32/esp
29054     # . save registers
29055     50/push-eax
29056     51/push-ecx
29057     52/push-edx
29058     53/push-ebx
29059     56/push-esi
29060     # esi = stmt
29061     8b/-> *(ebp+0xc) 6/r32/esi
29062     # var base/ebx: (addr var) = stmt->inouts[0]->value
29063     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
29064     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
29065     89/<- %ebx 0/r32/eax
29066     # var elemsize/ecx: int = array-element-size(base)
29067     (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
29068     89/<- %ecx 0/r32/eax
29069     # var outreg/edx: (addr array byte) = stmt->outputs[0]->value->register
29070     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
29071     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
29072     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
29073     89/<- %edx 0/r32/eax
29074     # if elemsize == 1
29075     {
29076       81 7/subop/compare %ecx 1/imm32
29077       75/jump-if-!= break/disp8
29078 $translate-mu-length-stmt:size-1:
29079       (emit-save-size-to *(ebp+8) %ebx %edx)
29080       e9/jump $translate-mu-length-stmt:end/disp32
29081     }
29082     # if elemsize is a power of 2 less than 256
29083     {
29084       (power-of-2? %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
29085       3d/compare-eax-and 0/imm32/false
29086       74/jump-if-= break/disp8
29087       81 7/subop/compare %ecx 0xff/imm32
29088       7f/jump-if-> break/disp8
29089 $translate-mu-length-stmt:size-power-of-2:
29090       (emit-save-size-to *(ebp+8) %ebx %edx)
29091       (emit-divide-by-shift-right *(ebp+8) %edx %ecx)
29092       e9/jump $translate-mu-length-stmt:end/disp32
29093     }
29094     # otherwise, the complex case
29095     # . emit register spills
29096     {
29097 $translate-mu-length-stmt:complex:
29098       (string-equal? %edx "eax")  # => eax
29099       3d/compare-eax-and 0/imm32/false
29100       75/break-if-!= break/disp8
29101       (emit-indent *(ebp+8) *Curr-block-depth)
29102       (write-buffered *(ebp+8) "50/push-eax\n")
29103     }
29104     {
29105       (string-equal? %edx "ecx")  # => eax
29106       3d/compare-eax-and 0/imm32/false
29107       75/break-if-!= break/disp8
29108       (emit-indent *(ebp+8) *Curr-block-depth)
29109       (write-buffered *(ebp+8) "51/push-ecx\n")
29110     }
29111     {
29112       (string-equal? %edx "edx")  # => eax
29113       3d/compare-eax-and 0/imm32/false
29114       75/break-if-!= break/disp8
29115       (emit-indent *(ebp+8) *Curr-block-depth)
29116       (write-buffered *(ebp+8) "52/push-edx\n")
29117     }
29118     # .
29119     (emit-save-size-to *(ebp+8) %ebx "eax")
29120     (emit-indent *(ebp+8) *Curr-block-depth)
29121     (write-buffered *(ebp+8) "31/xor %edx 2/r32/edx\n")
29122     (emit-indent *(ebp+8) *Curr-block-depth)
29123     (write-buffered *(ebp+8) "b9/copy-to-ecx ")
29124     (write-int32-hex-buffered *(ebp+8) %ecx)
29125     (write-buffered *(ebp+8) "/imm32\n")
29126     (emit-indent *(ebp+8) *Curr-block-depth)
29127     (write-buffered *(ebp+8) "f7 7/subop/idiv-eax-edx-by %ecx\n")
29128     {
29129       (string-equal? %edx "eax")  # => eax
29130       3d/compare-eax-and 0/imm32/false
29131       75/break-if-!= break/disp8
29132       (emit-indent *(ebp+8) *Curr-block-depth)
29133       (write-buffered *(ebp+8) "89/<- %")
29134       (write-buffered *(ebp+8) %edx)
29135       (write-buffered *(ebp+8) " 0/r32/eax\n")
29136     }
29137     # . emit register restores
29138     {
29139       (string-equal? %edx "edx")  # => eax
29140       3d/compare-eax-and 0/imm32/false
29141       75/break-if-!= break/disp8
29142       (emit-indent *(ebp+8) *Curr-block-depth)
29143       (write-buffered *(ebp+8) "5a/pop-to-edx\n")
29144     }
29145     {
29146       (string-equal? %edx "ecx")  # => eax
29147       3d/compare-eax-and 0/imm32/false
29148       75/break-if-!= break/disp8
29149       (emit-indent *(ebp+8) *Curr-block-depth)
29150       (write-buffered *(ebp+8) "59/pop-to-ecx\n")
29151     }
29152     {
29153       (string-equal? %edx "eax")  # => eax
29154       3d/compare-eax-and 0/imm32/false
29155       75/break-if-!= break/disp8
29156       (emit-indent *(ebp+8) *Curr-block-depth)
29157       (write-buffered *(ebp+8) "58/pop-to-eax\n")
29158     }
29159 $translate-mu-length-stmt:end:
29160     # . restore registers
29161     5e/pop-to-esi
29162     5b/pop-to-ebx
29163     5a/pop-to-edx
29164     59/pop-to-ecx
29165     58/pop-to-eax
29166     # . epilogue
29167     89/<- %esp 5/r32/ebp
29168     5d/pop-to-ebp
29169     c3/return
29171 array-element-size:  # arr: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
29172     # . prologue
29173     55/push-ebp
29174     89/<- %ebp 4/r32/esp
29175     #
29176     (array-element-type-id *(ebp+8) *(ebp+0xc) *(ebp+0x10))  # => eax
29177     (size-of-type-id-as-array-element %eax)  # => eax
29178 $array-element-size:end:
29179     # . epilogue
29180     89/<- %esp 5/r32/ebp
29181     5d/pop-to-ebp
29182     c3/return
29184 array-element-type-id:  # v: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: type-id
29185     # precondition: n is positive
29186     # . prologue
29187     55/push-ebp
29188     89/<- %ebp 4/r32/esp
29189     #
29190     8b/-> *(ebp+8) 0/r32/eax
29191     # var t/eax: (addr type-tree)
29192     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
29193     # if t == 0 abort
29194     3d/compare-eax-with 0/imm32
29195     0f 84/jump-if-== $array-element-type-id:error0/disp32
29196     # if t->is-atom? abort
29197     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
29198     0f 85/jump-if-!= $array-element-type-id:error1/disp32
29199     # if (t->left == addr) t = t->right
29200     {
29201       50/push-eax
29202       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
29203       (simple-mu-type? %eax 2)  # addr => eax
29204       3d/compare-eax-with 0/imm32/false
29205       58/pop-to-eax
29206       74/jump-if-= break/disp8
29207 $array-element-type-id:skip-addr:
29208       (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
29209     }
29210     # if t == 0 abort
29211     3d/compare-eax-with 0/imm32
29212     0f 84/jump-if-= $array-element-type-id:error2/disp32
29213     # if t->is-atom? abort
29214     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
29215     0f 85/jump-if-!= $array-element-type-id:error2/disp32
29216     # if t->left != array abort
29217     {
29218       50/push-eax
29219       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
29220       (simple-mu-type? %eax 3)  # array => eax
29221       3d/compare-eax-with 0/imm32/false
29222       58/pop-to-eax
29223 $array-element-type-id:no-array:
29224       0f 84/jump-if-= $array-element-type-id:error2/disp32
29225     }
29226 $array-element-type-id:skip-array:
29227     # t = t->right
29228     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
29229     # if t == 0 abort
29230     3d/compare-eax-with 0/imm32
29231     0f 84/jump-if-= $array-element-type-id:error2/disp32
29232     # if t->is-atom? abort
29233     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
29234     0f 85/jump-if-!= $array-element-type-id:error2/disp32
29235     # t = t->left
29236     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
29237     # if (!t->is-atom?) t = t->left     # TODO: assumes array element size can be determined from just first word of array element type
29238     # if (t->is-atom == false) t = lookup(t->left)
29239     {
29240       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
29241       75/jump-if-!= break/disp8
29242       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
29243     }
29244     # return t->value
29245     8b/-> *(eax+4) 0/r32/eax  # Type-tree-value
29246 $array-element-type-id:end:
29247     # . epilogue
29248     89/<- %esp 5/r32/ebp
29249     5d/pop-to-ebp
29250     c3/return
29252 $array-element-type-id:error0:
29253     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
29254     50/push-eax
29255     8b/-> *(ebp+8) 0/r32/eax
29256     (lookup *eax *(eax+4))  # Var-name Var-name => eax
29257     (write-buffered *(ebp+0xc) %eax)
29258     58/pop-to-eax
29259     (write-buffered *(ebp+0xc) "' has no type\n")
29260     (flush *(ebp+0xc))
29261     (stop *(ebp+0x10) 1)
29262     # never gets here
29264 $array-element-type-id:error1:
29265     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
29266     50/push-eax
29267     8b/-> *(ebp+8) 0/r32/eax
29268     (lookup *eax *(eax+4))  # Var-name Var-name => eax
29269     (write-buffered *(ebp+0xc) %eax)
29270     58/pop-to-eax
29271     (write-buffered *(ebp+0xc) "' has atomic type ")
29272     (write-int32-hex-buffered *(ebp+0xc) *(eax+4))  # Type-tree-value
29273     (write-buffered *(ebp+0xc) Newline)
29274     (flush *(ebp+0xc))
29275     (stop *(ebp+0x10) 1)
29276     # never gets here
29278 $array-element-type-id:error2:
29279     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
29280     50/push-eax
29281     8b/-> *(ebp+8) 0/r32/eax
29282     (lookup *eax *(eax+4))  # Var-name Var-name => eax
29283     (write-buffered *(ebp+0xc) %eax)
29284     58/pop-to-eax
29285     (write-buffered *(ebp+0xc) "' has non-array type\n")
29286     (flush *(ebp+0xc))
29287     (stop *(ebp+0x10) 1)
29288     # never gets here
29290 size-of-type-id-as-array-element:  # t: type-id -> result/eax: int
29291     # . prologue
29292     55/push-ebp
29293     89/<- %ebp 4/r32/esp
29294     # eax = t
29295     8b/-> *(ebp+8) 0/r32/eax
29296     # if t is 'byte', size is 1
29297     3d/compare-eax-and 8/imm32/byte
29298     {
29299       75/jump-if-!= break/disp8
29300       b8/copy-to-eax 1/imm32
29301       eb/jump $size-of-type-id-as-array-element:end/disp8
29302     }
29303     # otherwise proceed as usual
29304     (size-of-type-id %eax)  # => eax
29305 $size-of-type-id-as-array-element:end:
29306     # . epilogue
29307     89/<- %esp 5/r32/ebp
29308     5d/pop-to-ebp
29309     c3/return
29311 stream-element-type-id:  # type: (addr type-tree), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: type-id
29312     # precondition: n is positive
29313     # . prologue
29314     55/push-ebp
29315     89/<- %ebp 4/r32/esp
29316     # eax = type
29317     8b/-> *(ebp+8) 0/r32/eax
29318     # if type == 0 abort
29319     3d/compare-eax-with 0/imm32
29320     0f 84/jump-if-== $stream-element-type-id:error0/disp32
29321     # if type->is-atom? abort
29322     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
29323     0f 85/jump-if-!= $stream-element-type-id:error1/disp32
29324     # if (type->left == addr) type = type->right
29325     {
29326       50/push-eax
29327       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
29328       (simple-mu-type? %eax 2)  # addr => eax
29329       3d/compare-eax-with 0/imm32/false
29330       58/pop-to-eax
29331       74/jump-if-= break/disp8
29332 $stream-element-type-id:skip-addr:
29333       (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
29334     }
29335     # if type == 0 abort
29336     3d/compare-eax-with 0/imm32
29337     0f 84/jump-if-= $stream-element-type-id:error2/disp32
29338     # if type->is-atom? abort
29339     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
29340     0f 85/jump-if-!= $stream-element-type-id:error2/disp32
29341     # if type->left != stream abort
29342     {
29343       50/push-eax
29344       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
29345       (simple-mu-type? %eax 0xb)  # stream => eax
29346       3d/compare-eax-with 0/imm32/false
29347       58/pop-to-eax
29348 $stream-element-type-id:no-stream:
29349       0f 84/jump-if-= $stream-element-type-id:error2/disp32
29350     }
29351 $stream-element-type-id:skip-stream:
29352     # type = type->right
29353     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
29354     # if type == 0 abort
29355     3d/compare-eax-with 0/imm32
29356     0f 84/jump-if-= $stream-element-type-id:error2/disp32
29357     # if type->is-atom? abort
29358     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
29359     0f 85/jump-if-!= $stream-element-type-id:error2/disp32
29360     # t = type->left
29361     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
29362     # if (!type->is-atom?) type = type->left     # TODO: assumes stream element size can be determined from just first word of stream element type
29363     {
29364       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
29365       75/jump-if-!= break/disp8
29366       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
29367     }
29368     # return type->value
29369     8b/-> *(eax+4) 0/r32/eax  # Type-tree-value
29370 $stream-element-type-id:end:
29371     # . epilogue
29372     89/<- %esp 5/r32/ebp
29373     5d/pop-to-ebp
29374     c3/return
29376 $stream-element-type-id:error0:
29377     (write-buffered *(ebp+0xc) "stream-element-type-id: var '")
29378     50/push-eax
29379     8b/-> *(ebp+8) 0/r32/eax
29380     (lookup *eax *(eax+4))  # Var-name Var-name => eax
29381     (write-buffered *(ebp+0xc) %eax)
29382     58/pop-to-eax
29383     (write-buffered *(ebp+0xc) "' has no type\n")
29384     (flush *(ebp+0xc))
29385     (stop *(ebp+0x10) 1)
29386     # never gets here
29388 $stream-element-type-id:error1:
29389     (write-buffered *(ebp+0xc) "stream-element-type-id: var '")
29390     50/push-eax
29391     8b/-> *(ebp+8) 0/r32/eax
29392     (lookup *eax *(eax+4))  # Var-name Var-name => eax
29393     (write-buffered *(ebp+0xc) %eax)
29394     58/pop-to-eax
29395     (write-buffered *(ebp+0xc) "' has atomic type ")
29396     (write-int32-hex-buffered *(ebp+0xc) *(eax+4))  # Type-tree-value
29397     (write-buffered *(ebp+0xc) Newline)
29398     (flush *(ebp+0xc))
29399     (stop *(ebp+0x10) 1)
29400     # never gets here
29402 $stream-element-type-id:error2:
29403     (write-buffered *(ebp+0xc) "stream-element-type-id: var '")
29404     50/push-eax
29405     8b/-> *(ebp+8) 0/r32/eax
29406     (lookup *eax *(eax+4))  # Var-name Var-name => eax
29407     (write-buffered *(ebp+0xc) %eax)
29408     58/pop-to-eax
29409     (write-buffered *(ebp+0xc) "' has non-stream type\n")
29410     (flush *(ebp+0xc))
29411     (stop *(ebp+0x10) 1)
29412     # never gets here
29414 emit-save-size-to:  # out: (addr buffered-file), base: (addr var), outreg: (addr array byte)
29415     # . prologue
29416     55/push-ebp
29417     89/<- %ebp 4/r32/esp
29418     # . save registers
29419     50/push-eax
29420     53/push-ebx
29421     # ebx = base
29422     8b/-> *(ebp+0xc) 3/r32/ebx
29423     (emit-indent *(ebp+8) *Curr-block-depth)
29424     (write-buffered *(ebp+8) "8b/-> *")
29425     # if base is an (addr array ...) in a register
29426     {
29427       81 7/subop/compare *(ebx+0x18)) 0/imm32  # Var-register
29428       74/jump-if-= break/disp8
29429 $emit-save-size-to:emit-base-from-register:
29430       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
29431       (write-buffered *(ebp+8) %eax)
29432       eb/jump $emit-save-size-to:emit-output/disp8
29433     }
29434     # otherwise if base is an (array ...) on the stack
29435     {
29436       81 7/subop/compare *(ebx+0x14)) 0/imm32  # Var-offset
29437       74/jump-if-= break/disp8
29438 $emit-save-size-to:emit-base-from-stack:
29439       (write-buffered *(ebp+8) "(ebp+")
29440       (write-int32-hex-buffered *(ebp+8) *(ebx+0x14))  # Var-offset
29441       (write-buffered *(ebp+8) ")")
29442     }
29443 $emit-save-size-to:emit-output:
29444     (write-buffered *(ebp+8) " ")
29445     (get Mu-registers *(ebp+0x10) 0xc "Mu-registers")  # => eax
29446     (write-int32-hex-buffered *(ebp+8) *eax)
29447     (write-buffered *(ebp+8) "/r32\n")
29448 $emit-save-size-to:end:
29449     # . restore registers
29450     5b/pop-to-ebx
29451     58/pop-to-eax
29452     # . epilogue
29453     89/<- %esp 5/r32/ebp
29454     5d/pop-to-ebp
29455     c3/return
29457 emit-divide-by-shift-right:  # out: (addr buffered-file), reg: (addr array byte), size: int
29458     # . prologue
29459     55/push-ebp
29460     89/<- %ebp 4/r32/esp
29461     # . save registers
29462     50/push-eax
29463     #
29464     (emit-indent *(ebp+8) *Curr-block-depth)
29465     (write-buffered *(ebp+8) "c1/shift 5/subop/>> %")
29466     (write-buffered *(ebp+8) *(ebp+0xc))
29467     (write-buffered *(ebp+8) Space)
29468     (num-shift-rights *(ebp+0x10))  # => eax
29469     (write-int32-hex-buffered *(ebp+8) %eax)
29470     (write-buffered *(ebp+8) "/imm8\n")
29471 $emit-divide-by-shift-right:end:
29472     # . restore registers
29473     58/pop-to-eax
29474     # . epilogue
29475     89/<- %esp 5/r32/ebp
29476     5d/pop-to-ebp
29477     c3/return
29479 translate-mu-copy-byte-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
29480     # . prologue
29481     55/push-ebp
29482     89/<- %ebp 4/r32/esp
29483     # . save registers
29484     50/push-eax
29485     56/push-esi
29486     # esi = stmt
29487     8b/-> *(ebp+0xc) 6/r32/esi
29488     #
29489     (emit-indent *(ebp+8) *Curr-block-depth)
29490     (write-buffered *(ebp+8) "8a/byte->")
29491     # emit stmt->inouts[0]
29492     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
29493     (emit-subx-var-as-rm32 *(ebp+8) %eax)
29494     # emit /r32 for stmt->outputs[0]->register
29495     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
29496     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
29497     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
29498     (maybe-get Mu-registers %eax 0xc)  # => eax: (addr register-index)
29499     (write-buffered *(ebp+8) Space)
29500     (write-int32-hex-buffered *(ebp+8) *eax)
29501     (write-buffered *(ebp+8) "/r32\n")
29502     # clear rest of register
29503     (emit-indent *(ebp+8) *Curr-block-depth)
29504     (write-buffered *(ebp+8) "81 4/subop/and %")
29505     8b/-> *(ebp+0xc) 0/r32/eax
29506     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
29507     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
29508     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
29509     (write-buffered *(ebp+8) %eax)
29510     (write-buffered *(ebp+8) " 0xff/imm32\n")
29511 $translate-mu-copy-byte-stmt:end:
29512     # . restore registers
29513     5e/pop-to-esi
29514     58/pop-to-eax
29515     # . epilogue
29516     89/<- %esp 5/r32/ebp
29517     5d/pop-to-ebp
29518     c3/return
29520 # a little different from other translate- functions; notice the extra 'fn' argument
29521 translate-mu-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
29522     # . prologue
29523     55/push-ebp
29524     89/<- %ebp 4/r32/esp
29525     # . save registers
29526     53/push-ebx
29527     # ebx = stmt
29528     8b/-> *(ebp+0xc) 3/r32/ebx
29529     # var base/ebx: (addr var) = stmt->inouts[0]
29530     (lookup *(ebx+0xc) *(ebx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
29531     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
29532     89/<- %ebx 0/r32/eax
29533     # emit bounds-check
29534     (emit-mu-index-bounds-check *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18))
29535     # if (var->register) do one thing
29536     {
29537       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
29538       74/jump-if-= break/disp8
29539       # TODO: ensure there's no dereference
29540       (translate-mu-index-stmt-with-array-in-register *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
29541       eb/jump $translate-mu-index-stmt:end/disp8
29542     }
29543     # if (var->offset) do a different thing
29544     {
29545       81 7/subop/compare *(ebx+0x14) 0/imm32  # Var-offset
29546       74/jump-if-= break/disp8
29547       # TODO: ensure there's no dereference
29548       (translate-mu-index-stmt-with-array-on-stack *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
29549       eb/jump $translate-mu-index-stmt:end/disp8
29550     }
29551 $translate-mu-index-stmt:end:
29552     # . restore registers
29553     5b/pop-to-ebx
29554     # . epilogue
29555     89/<- %esp 5/r32/ebp
29556     5d/pop-to-ebp
29557     c3/return
29559 $translate-mu-index-stmt:error1:
29560     (write-buffered *(ebp+0x14) "couldn't translate an index instruction. second (index) input must either lie in a register or be a literal\n")
29561     (flush *(ebp+0x14))
29562     (stop *(ebp+0x18) 1)
29563     # never gets here
29565 $translate-mu-index-stmt:error2:
29566     (write-buffered *(ebp+0x14) "couldn't translate an index instruction. second (index) input when in a register must be an int or offset\n")
29567     (flush *(ebp+0x14))
29568     (stop *(ebp+0x18) 1)
29569     # never gets here
29571 emit-mu-index-bounds-check:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
29572     # . prologue
29573     55/push-ebp
29574     89/<- %ebp 4/r32/esp
29575     # . save registers
29576     50/push-eax
29577     51/push-ecx
29578     52/push-edx
29579     53/push-ebx
29580     # ecx = stmt
29581     8b/-> *(ebp+0xc) 1/r32/ecx
29582     #
29583     (emit-indent *(ebp+8) *Curr-block-depth)
29584     (write-buffered *(ebp+8) "(__check-mu-array-bounds ")
29585 $emit-mu-index-bounds-check:compute-base:
29586     # var base/ebx: (addr var) = inouts[0]
29587     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
29588     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
29589     89/<- %ebx 0/r32/eax
29590 $emit-mu-index-bounds-check:emit-index:
29591     # var index/edx: (addr var) = inouts[1]
29592     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
29593     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
29594     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
29595     89/<- %edx 0/r32/eax
29596     # if index->register, print its code
29597     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
29598     {
29599       0f 84/jump-if-= break/disp32
29600 $emit-mu-index-bounds-check:emit-register-index:
29601       (write-buffered *(ebp+8) "%")
29602       (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
29603       (write-buffered *(ebp+8) %eax)
29604       eb/jump $emit-mu-index-bounds-check:index-done/disp8
29605     }
29606     # otherwise if index is a literal, print it
29607 $emit-mu-index-bounds-check:emit-literal-index:
29608     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
29609     (simple-mu-type? %eax 0)  # => eax
29610     3d/compare-eax-and 0/imm32/false
29611     {
29612       0f 84/jump-if-= break/disp32
29613       (lookup *edx *(edx+4))  # Var-name Var-name => eax
29614       (write-buffered *(ebp+8) %eax)
29615     }
29616 $emit-mu-index-bounds-check:index-done:
29617     (write-buffered *(ebp+8) " ")
29618 $emit-mu-index-bounds-check:emit-element-size:
29619     # if index is a literal or int, print size of array element
29620     {
29621       {
29622         (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
29623         (simple-mu-type? %eax 0)  # literal => eax
29624         3d/compare-eax-and 0/imm32/false
29625         75/jump-if-!= break/disp8
29626         (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
29627         (simple-mu-type? %eax 1)  # int => eax
29628         3d/compare-eax-and 0/imm32/false
29629         75/jump-if-!= break/disp8
29630         eb/jump $emit-mu-index-bounds-check:emit-element-size-offset/disp8
29631       }
29632 $emit-mu-index-bounds-check:emit-int-register-index:
29633       (array-element-size %ebx *(ebp+0x14) *(ebp+0x18))  # => eax
29634       (write-int32-hex-buffered *(ebp+8) %eax)
29635       e9/jump $emit-mu-index-bounds-check:emit-base/disp32
29636     }
29637 $emit-mu-index-bounds-check:emit-element-size-offset:
29638     # if index has type (offset ...), print "1"
29639     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
29640     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
29641     {
29642       75/jump-if-!= break/disp8
29643       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
29644       (simple-mu-type? %eax 7)  # => eax
29645       3d/compare-eax-and 0/imm32/false
29646       {
29647         0f 84/jump-if-= break/disp32
29648 $emit-mu-index-bounds-check:emit-offset-register-index:
29649         (write-buffered *(ebp+8) "1")
29650       }
29651     }
29652 $emit-mu-index-bounds-check:emit-base:
29653     # if base is in a register, print " *" base->register
29654     81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
29655     {
29656       74/jump-if-= break/disp8
29657       (write-buffered *(ebp+8) " *")
29658       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
29659       (write-buffered *(ebp+8) %eax)
29660       e9/jump $emit-mu-index-bounds-check:emit-function-name/disp32
29661     }
29662     # otherwise print " *(ebp+" base->offset ")"
29663     (write-buffered *(ebp+8) " *(ebp+")
29664     (write-int32-hex-buffered *(ebp+8) *(ebx+0x14))  # Var-offset
29665     (write-buffered *(ebp+8) ")")
29666 $emit-mu-index-bounds-check:emit-function-name:
29667     # " \"" function-name "\""
29668     (write-buffered *(ebp+8) " \"")
29669     8b/-> *(ebp+0x10) 1/r32/ecx
29670     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
29671     (write-buffered *(ebp+8) %eax)
29672     (write-buffered *(ebp+8) "\"")
29673 $emit-mu-index-bounds-check:emit-array-name:
29674     # " \"" base->name "\""
29675     (write-buffered *(ebp+8) " \"")
29676     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
29677     (write-buffered *(ebp+8) %eax)
29678     (write-buffered *(ebp+8) "\")\n")
29679 $emit-mu-index-bounds-check:end:
29680     # . restore registers
29681     5b/pop-to-ebx
29682     5a/pop-to-edx
29683     59/pop-to-ecx
29684     58/pop-to-eax
29685     # . epilogue
29686     89/<- %esp 5/r32/ebp
29687     5d/pop-to-ebp
29688     c3/return
29690 translate-mu-index-stmt-with-array-in-register:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
29691     # . prologue
29692     55/push-ebp
29693     89/<- %ebp 4/r32/esp
29694     # . save registers
29695     50/push-eax
29696     51/push-ecx
29697     52/push-edx
29698     53/push-ebx
29699     # ecx = stmt
29700     8b/-> *(ebp+0xc) 1/r32/ecx
29701     # var base/ebx: (addr var) = inouts[0]
29702     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
29703     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
29704     89/<- %ebx 0/r32/eax
29705     # emit null check
29706     (emit-indent *(ebp+8) *Curr-block-depth)
29707     (write-buffered *(ebp+8) "81 7/subop/compare %")
29708     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
29709     (write-buffered *(ebp+8) %eax)
29710     (write-buffered *(ebp+8) " 0/imm32\n")
29711     (emit-indent *(ebp+8) *Curr-block-depth)
29712     (write-buffered *(ebp+8) "0f 84/jump-if-= __mu-abort-null-index-base-address/disp32\n")
29713     #
29714     (emit-indent *(ebp+8) *Curr-block-depth)
29715     (write-buffered *(ebp+8) "8d/copy-address *(")
29716     # TODO: ensure inouts[0] is in a register and not dereferenced
29717 $translate-mu-index-stmt-with-array-in-register:emit-base:
29718     # print base->register " + "
29719     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
29720     (write-buffered *(ebp+8) %eax)
29721     (write-buffered *(ebp+8) " + ")
29722     # var index/edx: (addr var) = inouts[1]
29723     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
29724     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
29725     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
29726     89/<- %edx 0/r32/eax
29727     # if index->register
29728     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
29729     {
29730       0f 84/jump-if-= break/disp32
29731 $translate-mu-index-stmt-with-array-in-register:emit-register-index:
29732       # if index is an int
29733       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
29734       (simple-mu-type? %eax 1)  # int => eax
29735       3d/compare-eax-and 0/imm32/false
29736       {
29737         0f 84/jump-if-= break/disp32
29738 $translate-mu-index-stmt-with-array-in-register:emit-int-register-index:
29739         # print index->register "<<" log2(array-element-size(base)) " + 4) "
29740         # . index->register "<<"
29741         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
29742         (write-buffered *(ebp+8) %eax)
29743         (write-buffered *(ebp+8) "<<")
29744         # . log2(array-element-size(base->type))
29745         # we know size is a power of 2
29746         (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
29747         (num-shift-rights %eax)  # => eax
29748         (write-int32-hex-buffered *(ebp+8) %eax)
29749         e9/jump $translate-mu-index-stmt-with-array-in-register:emit-register-index-done/disp32
29750       }
29751       # if index->type is any other atom, abort
29752       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
29753       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
29754       0f 85/jump-if-!= $translate-mu-index-stmt:error2/disp32
29755       # if index has type (offset ...)
29756       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
29757       (simple-mu-type? %eax 7)  # => eax
29758       3d/compare-eax-and 0/imm32/false
29759       {
29760         0f 84/jump-if-= break/disp32
29761         # print index->register
29762 $translate-mu-index-stmt-with-array-in-register:emit-offset-register-index:
29763         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
29764         (write-buffered *(ebp+8) %eax)
29765       }
29766 $translate-mu-index-stmt-with-array-in-register:emit-register-index-done:
29767       (write-buffered *(ebp+8) " + 4) ")
29768       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
29769     }
29770     # otherwise if index is a literal
29771     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
29772     (simple-mu-type? %eax 0)  # => eax
29773     3d/compare-eax-and 0/imm32/false
29774     {
29775       0f 84/jump-if-= break/disp32
29776 $translate-mu-index-stmt-with-array-in-register:emit-literal-index:
29777       # var index-value/edx: int = parse-hex-int(index->name)
29778       (lookup *edx *(edx+4))  # Var-name Var-name => eax
29779       (parse-hex-int %eax)  # => eax
29780       89/<- %edx 0/r32/eax
29781       # offset = idx-value * array-element-size(base->type)
29782       (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
29783       f7 4/subop/multiply-into-edx-eax %edx  # clobbers edx
29784       # offset += 4 for array size
29785       05/add-to-eax 4/imm32
29786       # TODO: check edx for overflow
29787       # print offset
29788       (write-int32-hex-buffered *(ebp+8) %eax)
29789       (write-buffered *(ebp+8) ") ")
29790       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
29791     }
29792     # otherwise abort
29793     e9/jump $translate-mu-index-stmt:error1/disp32
29794 $translate-mu-index-stmt-with-array-in-register:emit-output:
29795     # outputs[0] "/r32"
29796     8b/-> *(ebp+0xc) 1/r32/ecx
29797     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
29798     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
29799     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
29800     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
29801     (write-int32-hex-buffered *(ebp+8) *eax)
29802     (write-buffered *(ebp+8) "/r32\n")
29803 $translate-mu-index-stmt-with-array-in-register:end:
29804     # . restore registers
29805     5b/pop-to-ebx
29806     5a/pop-to-edx
29807     59/pop-to-ecx
29808     58/pop-to-eax
29809     # . epilogue
29810     89/<- %esp 5/r32/ebp
29811     5d/pop-to-ebp
29812     c3/return
29814 translate-mu-index-stmt-with-array-on-stack:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
29815     # . prologue
29816     55/push-ebp
29817     89/<- %ebp 4/r32/esp
29818     # . save registers
29819     50/push-eax
29820     51/push-ecx
29821     52/push-edx
29822     53/push-ebx
29823     #
29824     (emit-indent *(ebp+8) *Curr-block-depth)
29825     (write-buffered *(ebp+8) "8d/copy-address *(ebp + ")
29826     # var curr/edx: (addr stmt-var) = lookup(stmt->inouts)
29827     8b/-> *(ebp+0xc) 0/r32/eax
29828     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
29829     89/<- %edx 0/r32/eax
29830     # var base/ecx: (addr var) = lookup(curr->value)
29831     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
29832     89/<- %ecx 0/r32/eax
29833     # var curr2/eax: (addr stmt-var) = lookup(curr->next)
29834     (lookup *(edx+8) *(edx+0xc))  # Stmt-var-next Stmt-var-next => eax
29835     # var index/edx: (handle var) = curr2->value
29836     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
29837     89/<- %edx 0/r32/eax
29838     # if index->register
29839     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
29840     {
29841       0f 84/jump-if-= break/disp32
29842 $translate-mu-index-stmt-with-array-on-stack:emit-register-index:
29843       # if index is an int
29844       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
29845       (simple-mu-type? %eax 1)  # int => eax
29846       3d/compare-eax-and 0/imm32/false
29847       {
29848         0f 84/jump-if-= break/disp32
29849 $translate-mu-index-stmt-with-array-on-stack:emit-int-register-index:
29850         # print index->register "<<" log2(array-element-size(base)) " + " base->offset+4
29851         # . inouts[1]->register "<<"
29852         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
29853         (write-buffered *(ebp+8) %eax)
29854         (write-buffered *(ebp+8) "<<")
29855         # . log2(array-element-size(base))
29856         # TODO: ensure size is a power of 2
29857         (array-element-size %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
29858         (num-shift-rights %eax)  # => eax
29859         (write-int32-hex-buffered *(ebp+8) %eax)
29860         #
29861         (write-buffered *(ebp+8) " + ")
29862         #
29863         8b/-> *(ecx+0x14) 0/r32/eax  # Var-offset
29864         05/add-to-eax 4/imm32  # for array length
29865         (write-int32-hex-buffered *(ebp+8) %eax)
29866         e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done/disp32
29867       }
29868       # if index->type is any other atom, abort
29869       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
29870       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
29871       0f 85/jump-if-!= $translate-mu-index-stmt:error2/disp32
29872       # if index has type (offset ...)
29873       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
29874       (simple-mu-type? %eax 7)  # => eax
29875       3d/compare-eax-and 0/imm32/false
29876       {
29877         0f 84/jump-if-= break/disp32
29878         # print index->register
29879 $translate-mu-index-stmt-with-array-on-stack:emit-offset-register-index:
29880         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
29881         (write-buffered *(ebp+8) %eax)
29882       }
29883 $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done:
29884       (write-buffered *(ebp+8) ") ")
29885       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
29886     }
29887     # otherwise if index is a literal
29888     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
29889     (simple-mu-type? %eax 0)  # => eax
29890     3d/compare-eax-and 0/imm32/false
29891     {
29892       0f 84/jump-if-= break/disp32
29893 $translate-mu-index-stmt-with-array-on-stack:emit-literal-index:
29894       # var idx-value/edx: int = parse-hex-int(index->name)
29895       (lookup *edx *(edx+4))  # Var-name Var-name => eax
29896       (parse-hex-int %eax)  # => eax
29897       89/<- %edx 0/r32/eax
29898       # offset = idx-value * array-element-size(base)
29899       (array-element-size %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
29900       f7 4/subop/multiply-into-edx-eax %edx  # clobbers edx
29901       # offset += base->offset
29902       03/add *(ecx+0x14) 0/r32/eax  # Var-offset
29903       # offset += 4 for array size
29904       05/add-to-eax 4/imm32
29905       # TODO: check edx for overflow
29906       # print offset
29907       (write-int32-hex-buffered *(ebp+8) %eax)
29908       (write-buffered *(ebp+8) ") ")
29909       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
29910     }
29911     # otherwise abort
29912     e9/jump $translate-mu-index-stmt:error1/disp32
29913 $translate-mu-index-stmt-with-array-on-stack:emit-output:
29914     # outputs[0] "/r32"
29915     8b/-> *(ebp+0xc) 0/r32/eax
29916     (lookup *(eax+0x14) *(eax+0x18))  # Stmt1-outputs Stmt1-outputs => eax
29917     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
29918     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
29919     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
29920     (write-int32-hex-buffered *(ebp+8) *eax)
29921     (write-buffered *(ebp+8) "/r32\n")
29922 $translate-mu-index-stmt-with-array-on-stack:end:
29923     # . restore registers
29924     5b/pop-to-ebx
29925     5a/pop-to-edx
29926     59/pop-to-ecx
29927     58/pop-to-eax
29928     # . epilogue
29929     89/<- %esp 5/r32/ebp
29930     5d/pop-to-ebp
29931     c3/return
29933 translate-mu-compute-offset-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
29934     # . prologue
29935     55/push-ebp
29936     89/<- %ebp 4/r32/esp
29937     # . save registers
29938     50/push-eax
29939     # var index-type/eax: (addr type-tree) = stmt->inouts->next->value->type
29940     8b/-> *(ebp+0xc) 0/r32/eax
29941     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
29942     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
29943     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
29944     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
29945     (simple-mu-type? %eax 0)  # literal => eax
29946     3d/compare-eax-and 0/imm32/false
29947     {
29948       74/jump-if-= break/disp8
29949       # special-case: index is a literal
29950       (translate-mu-compute-offset-stmt-with-literal-index *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
29951       eb/jump $translate-mu-compute-offset-stmt:end/disp8
29952     }
29953     (translate-mu-compute-offset-stmt-with-register-index *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
29954 $translate-mu-compute-offset-stmt:end:
29955     # . restore registers
29956     58/pop-to-eax
29957     # . epilogue
29958     89/<- %esp 5/r32/ebp
29959     5d/pop-to-ebp
29960     c3/return
29962 translate-mu-compute-offset-stmt-with-register-index:  # out: (addr buffered-file), stmt-with-register-index: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
29963     # . prologue
29964     55/push-ebp
29965     89/<- %ebp 4/r32/esp
29966     # . save registers
29967     50/push-eax
29968     51/push-ecx
29969     52/push-edx
29970     53/push-ebx
29971     #
29972     (emit-indent *(ebp+8) *Curr-block-depth)
29973     (write-buffered *(ebp+8) "69/multiply")
29974     # ecx = stmt
29975     8b/-> *(ebp+0xc) 1/r32/ecx
29976     # var first-inout/ebx: (addr stmt-var) = stmt->inouts[0]
29977     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
29978     89/<- %ebx 0/r32/eax
29979 $translate-mu-compute-offset-stmt-with-register-index:emit-index:
29980     (lookup *(ebx+8) *(ebx+0xc))  # Stmt-var-next Stmt-var-next => eax
29981     (emit-subx-var-as-rm32 *(ebp+8) %eax)
29982     (write-buffered *(ebp+8) Space)
29983 $translate-mu-compute-offset-stmt-with-register-index:emit-elem-size:
29984     # var base/ebx: (addr var)
29985     (lookup *ebx *(ebx+4))  # Stmt-var-value Stmt-var-value => eax
29986     89/<- %ebx 0/r32/eax
29987     # print array-element-size(base)
29988     (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
29989     (write-int32-hex-buffered *(ebp+8) %eax)
29990     (write-buffered *(ebp+8) "/imm32 ")
29991 $translate-mu-compute-offset-stmt-with-register-index:emit-output:
29992     # outputs[0] "/r32"
29993     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
29994     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
29995     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
29996     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
29997     (write-int32-hex-buffered *(ebp+8) *eax)
29998     (write-buffered *(ebp+8) "/r32\n")
29999 $translate-mu-compute-offset-stmt-with-register-index:end:
30000     # . restore registers
30001     5b/pop-to-ebx
30002     5a/pop-to-edx
30003     59/pop-to-ecx
30004     58/pop-to-eax
30005     # . epilogue
30006     89/<- %esp 5/r32/ebp
30007     5d/pop-to-ebp
30008     c3/return
30010 translate-mu-compute-offset-stmt-with-literal-index:  # out: (addr buffered-file), stmt-with-literal-index: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
30011     # . prologue
30012     55/push-ebp
30013     89/<- %ebp 4/r32/esp
30014     # . save registers
30015     50/push-eax
30016     51/push-ecx
30017     52/push-edx
30018     53/push-ebx
30019     #
30020     (emit-indent *(ebp+8) *Curr-block-depth)
30021     (write-buffered *(ebp+8) "c7/copy %")
30022     # ecx = stmt
30023     8b/-> *(ebp+0xc) 1/r32/ecx
30024 $translate-mu-compute-offset-stmt-with-literal-index:emit-output:
30025     # emit outputs[0]->register
30026     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
30027     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
30028     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
30029     (write-buffered *(ebp+8) %eax)
30030     (write-buffered *(ebp+8) Space)
30031 $translate-mu-compute-offset-stmt-with-literal-index:emit-offset:
30032     # var first-inout/ebx: (addr stmt-var) = stmt->inouts
30033     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
30034     89/<- %ebx 0/r32/eax
30035     # var index/edx: int = int(first-inout->next->value)
30036     (lookup *(ebx+8) *(ebx+0xc))  # Stmt-var-next Stmt-var-next => eax
30037     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
30038     (lookup *eax *(eax+4))  # Var-name Var-name => eax
30039     (parse-hex-int %eax)  # => eax
30040     89/<- %edx 0/r32/eax
30041     # var base/ebx: (addr var) = first-inout->value
30042     (lookup *ebx *(ebx+4))  # Stmt-var-value Stmt-var-value => eax
30043     # emit index * sizeof(base element type)
30044     (array-element-size %eax *(ebp+0x10) *(ebp+0x14))  # => eax
30045     0f af/multiply %edx 0/r32/eax
30046     (write-int32-hex-buffered *(ebp+8) %eax)
30047     (write-buffered *(ebp+8) "/imm32\n")
30048 $translate-mu-compute-offset-stmt-with-literal-index:end:
30049     # . restore registers
30050     5b/pop-to-ebx
30051     5a/pop-to-edx
30052     59/pop-to-ecx
30053     58/pop-to-eax
30054     # . epilogue
30055     89/<- %esp 5/r32/ebp
30056     5d/pop-to-ebp
30057     c3/return
30059 translate-mu-get-stmt:  # out: (addr buffered-file), stmt: (addr stmt)
30060     # . prologue
30061     55/push-ebp
30062     89/<- %ebp 4/r32/esp
30063     # . save registers
30064     50/push-eax
30065     51/push-ecx
30066     52/push-edx
30067     # ecx = stmt
30068     8b/-> *(ebp+0xc) 1/r32/ecx
30069     # var base/eax: (addr var) = stmt->inouts->value
30070     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
30071     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
30072     # if base is in a register, insert a null check
30073     81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
30074     {
30075       0f 84/jump-if-= break/disp32
30076 $translate-mu-get-stmt:emit-null-check-for-register-input:
30077       # emit "81 7/subop/compare %" base->register " 0/imm32\n"
30078       (emit-indent *(ebp+8) *Curr-block-depth)
30079       (write-buffered *(ebp+8) "81 7/subop/compare %")
30080       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
30081       (write-buffered *(ebp+8) %eax)
30082       (write-buffered *(ebp+8) " 0/imm32\n")
30083       #
30084       (emit-indent *(ebp+8) *Curr-block-depth)
30085       (write-buffered *(ebp+8) "0f 84/jump-if-= __mu-abort-null-get-base-address/disp32\n")
30086     }
30087     # var offset/edx: int = get offset of stmt
30088     (mu-get-offset %ecx)  # => eax
30089     89/<- %edx 0/r32/eax
30090     # var base/eax: (addr var) = stmt->inouts->value
30091     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
30092     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
30093     #
30094     (emit-indent *(ebp+8) *Curr-block-depth)
30095     (write-buffered *(ebp+8) "8d/copy-address ")
30096     # if base is in a register
30097     81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
30098     {
30099       0f 84/jump-if-= break/disp32
30100 $translate-mu-get-stmt:emit-register-input:
30101       # emit "*(" base->register " + " offset ") "
30102       (write-buffered *(ebp+8) "*(")
30103       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
30104       (write-buffered *(ebp+8) %eax)
30105       (write-buffered *(ebp+8) " + ")
30106       (write-int32-hex-buffered *(ebp+8) %edx)
30107       (write-buffered *(ebp+8) ") ")
30108       e9/jump $translate-mu-get-stmt:emit-output/disp32
30109     }
30110     # otherwise base is on the stack
30111     {
30112 $translate-mu-get-stmt:emit-stack-input:
30113       # emit "*(ebp + " inouts[0]->stack-offset + offset ") "
30114       (write-buffered *(ebp+8) "*(ebp+")
30115       03/add *(eax+0x14) 2/r32/edx  # Var-offset
30116       (write-int32-hex-buffered *(ebp+8) %edx)
30117       (write-buffered *(ebp+8) ") ")
30118       eb/jump $translate-mu-get-stmt:emit-output/disp8
30119     }
30120 $translate-mu-get-stmt:emit-output:
30121     # var output/eax: (addr var) = stmt->outputs->value
30122     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
30123     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
30124     # emit offset->register "/r32"
30125     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
30126     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
30127     (write-int32-hex-buffered *(ebp+8) *eax)
30128     (write-buffered *(ebp+8) "/r32\n")
30129 $translate-mu-get-stmt:end:
30130     # . restore registers
30131     5a/pop-to-edx
30132     59/pop-to-ecx
30133     58/pop-to-eax
30134     # . epilogue
30135     89/<- %esp 5/r32/ebp
30136     5d/pop-to-ebp
30137     c3/return
30139 translate-mu-copy-object-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
30140     # . prologue
30141     55/push-ebp
30142     89/<- %ebp 4/r32/esp
30143     # . save registers
30144     50/push-eax
30145     #
30146     (emit-indent *(ebp+8) *Curr-block-depth)
30147     (write-buffered *(ebp+8) "(copy-bytes")
30148     # eax = stmt
30149     8b/-> *(ebp+0xc) 0/r32/eax
30150     # var first-inout/eax: (addr stmt-var) = stmt->inouts[0]
30151     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
30152     (emit-subx-call-operand *(ebp+8) %eax)
30153     # var second-inout/eax: (addr stmt-var) = stmt->inouts[1]
30154     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
30155     (emit-subx-call-operand *(ebp+8) %eax)
30156     # emit size of inouts
30157     (write-buffered *(ebp+8) Space)
30158     (addr-payload-size %eax *(ebp+0x10) *(ebp+0x14))  # => eax
30159     (write-int32-hex-buffered *(ebp+8) %eax)
30160     (write-buffered *(ebp+8) ")\n")
30161 $translate-mu-copy-object-stmt:end:
30162     # . restore registers
30163     58/pop-to-eax
30164     # . epilogue
30165     89/<- %esp 5/r32/ebp
30166     5d/pop-to-ebp
30167     c3/return
30169 translate-mu-clear-object-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
30170     # . prologue
30171     55/push-ebp
30172     89/<- %ebp 4/r32/esp
30173     # . save registers
30174     50/push-eax
30175     #
30176     (emit-indent *(ebp+8) *Curr-block-depth)
30177     (write-buffered *(ebp+8) "(zero-out")
30178     # eax = stmt
30179     8b/-> *(ebp+0xc) 0/r32/eax
30180     # var dest/eax: (addr stmt-var) = stmt->inouts[0]
30181     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
30182     #
30183     (emit-subx-call-operand *(ebp+8) %eax)
30184     (write-buffered *(ebp+8) Space)
30185     (addr-payload-size %eax *(ebp+0x10) *(ebp+0x14))  # => eax
30186     (write-int32-hex-buffered *(ebp+8) %eax)
30187     (write-buffered *(ebp+8) ")\n")
30188 $translate-mu-clear-object-stmt:end:
30189     # . restore registers
30190     58/pop-to-eax
30191     # . epilogue
30192     89/<- %esp 5/r32/ebp
30193     5d/pop-to-ebp
30194     c3/return
30196 translate-mu-allocate-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
30197     # . prologue
30198     55/push-ebp
30199     89/<- %ebp 4/r32/esp
30200     # . save registers
30201     50/push-eax
30202     56/push-esi
30203     57/push-edi
30204     # esi = stmt
30205     8b/-> *(ebp+0xc) 6/r32/esi
30206     # var target/edi: (addr stmt-var) = stmt->inouts[0]
30207     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
30208     89/<- %edi 0/r32/eax
30209     #
30210     (emit-indent *(ebp+8) *Curr-block-depth)
30211     (write-buffered *(ebp+8) "(allocate Heap ")
30212     (addr-handle-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
30213     (write-int32-hex-buffered *(ebp+8) %eax)
30214     (emit-subx-call-operand *(ebp+8) %edi)
30215     (write-buffered *(ebp+8) ")\n")
30216 $translate-mu-allocate-stmt:end:
30217     # . restore registers
30218     5f/pop-to-edi
30219     5e/pop-to-esi
30220     58/pop-to-eax
30221     # . epilogue
30222     89/<- %esp 5/r32/ebp
30223     5d/pop-to-ebp
30224     c3/return
30226 addr-handle-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
30227     # . prologue
30228     55/push-ebp
30229     89/<- %ebp 4/r32/esp
30230     # var t/eax: (addr type-tree) = s->value->type
30231     8b/-> *(ebp+8) 0/r32/eax
30232     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
30233     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
30234     # TODO: check eax != 0
30235     # TODO: check !t->is-atom?
30236     # TODO: check t->left == addr
30237     # t = t->right
30238 $addr-handle-payload-size:skip-addr:
30239     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
30240     # TODO: check eax != 0
30241     # TODO: check !t->is-atom?
30242     # TODO: check t->left == handle
30243     # t = t->right
30244 $addr-handle-payload-size:skip-handle:
30245     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
30246     # TODO: check eax != 0
30247     # if !t->is-atom? t = t->left
30248     81 7/subop/compare *eax 0/imm32/false
30249     {
30250       75/jump-if-!= break/disp8
30251       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
30252     }
30253     # TODO: check t->is-atom?
30254     # return size(t->value)
30255     (size-of-type-id *(eax+4))  # Type-tree-value => eax
30256 $addr-handle-payload-size:end:
30257     # . epilogue
30258     89/<- %esp 5/r32/ebp
30259     5d/pop-to-ebp
30260     c3/return
30262 addr-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
30263     # . prologue
30264     55/push-ebp
30265     89/<- %ebp 4/r32/esp
30266     # var t/eax: (addr type-tree) = s->value->type
30267     8b/-> *(ebp+8) 0/r32/eax
30268     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
30269     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
30270     # TODO: check eax != 0
30271     # TODO: check !t->is-atom?
30272     # TODO: check t->left == addr
30273     # t = t->right
30274 $addr-payload-size:skip-addr:
30275     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
30276     # TODO: check eax != 0
30277     # if !t->is-atom? t = t->left
30278     81 7/subop/compare *eax 0/imm32/false
30279     {
30280       75/jump-if-!= break/disp8
30281       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
30282     }
30283     # TODO: check t->is-atom?
30284     # return size(t->value)
30285     (size-of-type-id *(eax+4))  # Type-tree-value => eax
30286 $addr-payload-size:end:
30287     # . epilogue
30288     89/<- %esp 5/r32/ebp
30289     5d/pop-to-ebp
30290     c3/return
30292 translate-mu-populate-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
30293     # . prologue
30294     55/push-ebp
30295     89/<- %ebp 4/r32/esp
30296     # . save registers
30297     50/push-eax
30298     51/push-ecx
30299     56/push-esi
30300     57/push-edi
30301     # esi = stmt
30302     8b/-> *(ebp+0xc) 6/r32/esi
30303     # var target/edi: (addr stmt-var) = stmt->inouts[0]
30304     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
30305     89/<- %edi 0/r32/eax
30306     # var len/ecx: (addr stmt-var) = stmt->inouts[1]
30307     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
30308     89/<- %ecx 0/r32/eax
30309     #
30310     (emit-indent *(ebp+8) *Curr-block-depth)
30311     (write-buffered *(ebp+8) "(allocate-array2 Heap ")
30312     (addr-handle-array-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
30313     (write-int32-hex-buffered *(ebp+8) %eax)
30314     (emit-subx-call-operand *(ebp+8) %ecx)
30315     (emit-subx-call-operand *(ebp+8) %edi)
30316     (write-buffered *(ebp+8) ")\n")
30317 $translate-mu-populate-stmt:end:
30318     # . restore registers
30319     5f/pop-to-edi
30320     5e/pop-to-esi
30321     59/pop-to-ecx
30322     58/pop-to-eax
30323     # . epilogue
30324     89/<- %esp 5/r32/ebp
30325     5d/pop-to-ebp
30326     c3/return
30328 translate-mu-populate-stream-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
30329     # . prologue
30330     55/push-ebp
30331     89/<- %ebp 4/r32/esp
30332     # . save registers
30333     50/push-eax
30334     51/push-ecx
30335     56/push-esi
30336     57/push-edi
30337     # esi = stmt
30338     8b/-> *(ebp+0xc) 6/r32/esi
30339     # var target/edi: (addr stmt-var) = stmt->inouts[0]
30340     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
30341     89/<- %edi 0/r32/eax
30342     # var len/ecx: (addr stmt-var) = stmt->inouts[1]
30343     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
30344     89/<- %ecx 0/r32/eax
30345     #
30346     (emit-indent *(ebp+8) *Curr-block-depth)
30347     (write-buffered *(ebp+8) "(new-stream Heap ")
30348     (addr-handle-stream-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
30349     (write-int32-hex-buffered *(ebp+8) %eax)
30350     (emit-subx-call-operand *(ebp+8) %ecx)
30351     (emit-subx-call-operand *(ebp+8) %edi)
30352     (write-buffered *(ebp+8) ")\n")
30353 $translate-mu-populate-stream-stmt:end:
30354     # . restore registers
30355     5f/pop-to-edi
30356     5e/pop-to-esi
30357     59/pop-to-ecx
30358     58/pop-to-eax
30359     # . epilogue
30360     89/<- %esp 5/r32/ebp
30361     5d/pop-to-ebp
30362     c3/return
30364 translate-mu-read-from-stream-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
30365     # . prologue
30366     55/push-ebp
30367     89/<- %ebp 4/r32/esp
30368     # . save registers
30369     50/push-eax
30370     51/push-ecx
30371     56/push-esi
30372     57/push-edi
30373     # esi = stmt
30374     8b/-> *(ebp+0xc) 6/r32/esi
30375     # var stream/ecx: (addr stmt-var) = stmt->inouts[0]
30376     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
30377     89/<- %ecx 0/r32/eax
30378     # var target/edi: (addr stmt-var) = stmt->inouts[1]
30379     (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
30380     89/<- %edi 0/r32/eax
30381     #
30382     (emit-indent *(ebp+8) *Curr-block-depth)
30383     (write-buffered *(ebp+8) "(read-from-stream")
30384     (emit-subx-call-operand *(ebp+8) %ecx)
30385     (emit-subx-call-operand *(ebp+8) %edi)
30386     (write-buffered *(ebp+8) Space)
30387     (addr-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
30388     (write-int32-hex-buffered *(ebp+8) %eax)
30389     (write-buffered *(ebp+8) ")\n")
30390 $translate-mu-read-from-stream-stmt:end:
30391     # . restore registers
30392     5f/pop-to-edi
30393     5e/pop-to-esi
30394     59/pop-to-ecx
30395     58/pop-to-eax
30396     # . epilogue
30397     89/<- %esp 5/r32/ebp
30398     5d/pop-to-ebp
30399     c3/return
30401 translate-mu-write-to-stream-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
30402     # . prologue
30403     55/push-ebp
30404     89/<- %ebp 4/r32/esp
30405     # . save registers
30406     50/push-eax
30407     51/push-ecx
30408     56/push-esi
30409     57/push-edi
30410     # esi = stmt
30411     8b/-> *(ebp+0xc) 6/r32/esi
30412     # var stream/ecx: (addr stmt-var) = stmt->inouts[0]
30413     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
30414     89/<- %ecx 0/r32/eax
30415     # var target/edi: (addr stmt-var) = stmt->inouts[1]
30416     (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
30417     89/<- %edi 0/r32/eax
30418     #
30419     (emit-indent *(ebp+8) *Curr-block-depth)
30420     (write-buffered *(ebp+8) "(write-to-stream")
30421     (emit-subx-call-operand *(ebp+8) %ecx)
30422     (flush *(ebp+8))
30423     (emit-subx-call-operand *(ebp+8) %edi)
30424     (flush *(ebp+8))
30425     (write-buffered *(ebp+8) Space)
30426     (flush *(ebp+8))
30427     (addr-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
30428     (write-int32-hex-buffered *(ebp+8) %eax)
30429     (write-buffered *(ebp+8) ")\n")
30430 $translate-mu-write-to-stream-stmt:end:
30431     # . restore registers
30432     5f/pop-to-edi
30433     5e/pop-to-esi
30434     59/pop-to-ecx
30435     58/pop-to-eax
30436     # . epilogue
30437     89/<- %esp 5/r32/ebp
30438     5d/pop-to-ebp
30439     c3/return
30441 addr-handle-array-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
30442     # . prologue
30443     55/push-ebp
30444     89/<- %ebp 4/r32/esp
30445     # var t/eax: (addr type-tree) = s->value->type
30446     8b/-> *(ebp+8) 0/r32/eax
30447     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
30448     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
30449     # TODO: check eax != 0
30450     # TODO: check !t->is-atom?
30451     # TODO: check t->left == addr
30452     # t = t->right
30453 $addr-handle-array-payload-size:skip-addr:
30454     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
30455     # TODO: check eax != 0
30456     # TODO: check !t->is-atom?
30457     # TODO: check t->left == handle
30458     # t = t->right
30459 $addr-handle-array-payload-size:skip-handle:
30460     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
30461     # TODO: check eax != 0
30462     # TODO: check !t->is-atom?
30463     # TODO: check t->left == array
30464     # t = t->right
30465 $addr-handle-array-payload-size:skip-array:
30466     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
30467     # TODO: check eax != 0
30468     # if !t->is-atom? t = t->left
30469     81 7/subop/compare *eax 0/imm32/false
30470     {
30471       75/jump-if-!= break/disp8
30472       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
30473     }
30474 $addr-handle-array-payload-size:compute-size:
30475     # TODO: check t->is-atom?
30476     # return size(t->value)
30477     (size-of-type-id-as-array-element *(eax+4))  # Type-tree-value => eax
30478 $addr-handle-array-payload-size:end:
30479     # . epilogue
30480     89/<- %esp 5/r32/ebp
30481     5d/pop-to-ebp
30482     c3/return
30484 addr-handle-stream-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
30485     # . prologue
30486     55/push-ebp
30487     89/<- %ebp 4/r32/esp
30488     # var t/eax: (addr type-tree) = s->value->type
30489     8b/-> *(ebp+8) 0/r32/eax
30490     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
30491     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
30492     # TODO: check eax != 0
30493     # TODO: check !t->is-atom?
30494     # TODO: check t->left == addr
30495     # t = t->right
30496 $addr-handle-stream-payload-size:skip-addr:
30497     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
30498     # TODO: check eax != 0
30499     # TODO: check !t->is-atom?
30500     # TODO: check t->left == handle
30501     # t = t->right
30502 $addr-handle-stream-payload-size:skip-handle:
30503     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
30504     # TODO: check eax != 0
30505     # TODO: check !t->is-atom?
30506     # TODO: check t->left == stream
30507     # t = t->right
30508 $addr-handle-stream-payload-size:skip-stream:
30509     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
30510     # TODO: check eax != 0
30511     # if !t->is-atom? t = t->left
30512     81 7/subop/compare *eax 0/imm32/false
30513     {
30514       75/jump-if-!= break/disp8
30515       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
30516     }
30517 $addr-handle-stream-payload-size:compute-size:
30518     # TODO: check t->is-atom?
30519     # return size(t->value)
30520     (size-of-type-id-as-array-element *(eax+4))  # Type-tree-value => eax
30521 $addr-handle-stream-payload-size:end:
30522     # . epilogue
30523     89/<- %esp 5/r32/ebp
30524     5d/pop-to-ebp
30525     c3/return
30527 power-of-2?:  # n: int, err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: boolean
30528     # precondition: n is positive
30529     # . prologue
30530     55/push-ebp
30531     89/<- %ebp 4/r32/esp
30532     # eax = n
30533     8b/-> *(ebp+8) 0/r32/eax
30534     # if (n < 0) abort
30535     3d/compare-eax-with 0/imm32
30536     0f 8c/jump-if-< $power-of-2?:abort/disp32
30537     # var tmp/eax: int = n-1
30538     48/decrement-eax
30539     # var tmp2/eax: int = n & tmp
30540     23/and-> *(ebp+8) 0/r32/eax
30541     # return (tmp2 == 0)
30542     3d/compare-eax-and 0/imm32
30543     0f 94/set-byte-if-= %al
30544     25/and-eax-with 0xff/imm32
30545 $power-of-2?:end:
30546     # . epilogue
30547     89/<- %esp 5/r32/ebp
30548     5d/pop-to-ebp
30549     c3/return
30551 $power-of-2?:abort:
30552     (write-buffered *(ebp+0xc) "power-of-2?: negative number\n")
30553     (flush *(ebp+0xc))
30554     (stop *(ebp+0x10) 1)
30555     # never gets here
30557 num-shift-rights:  # n: int -> result/eax: int
30558     # precondition: n is a positive power of 2
30559     # . prologue
30560     55/push-ebp
30561     89/<- %ebp 4/r32/esp
30562     # . save registers
30563     51/push-ecx
30564     # var curr/ecx: int = n
30565     8b/-> *(ebp+8) 1/r32/ecx
30566     # result = 0
30567     b8/copy-to-eax 0/imm32
30568     {
30569       # if (curr <= 1) break
30570       81 7/subop/compare %ecx 1/imm32
30571       7e/jump-if-<= break/disp8
30572       40/increment-eax
30573       c1/shift 5/subop/arithmetic-right %ecx 1/imm8
30574       eb/jump loop/disp8
30575     }
30576 $num-shift-rights:end:
30577     # . restore registers
30578     59/pop-to-ecx
30579     # . epilogue
30580     89/<- %esp 5/r32/ebp
30581     5d/pop-to-ebp
30582     c3/return
30584 mu-get-offset:  # stmt: (addr stmt) -> result/eax: int
30585     # . prologue
30586     55/push-ebp
30587     89/<- %ebp 4/r32/esp
30588     # var second-inout/eax: (addr stmt-var) = stmt->inouts->next
30589     8b/-> *(ebp+8) 0/r32/eax
30590     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
30591     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
30592     # var output-var/eax: (addr var) = second-inout->value
30593     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
30594 #?     (write-buffered Stderr "mu-get-offset: ")
30595 #?     (write-int32-hex-buffered Stderr %eax)
30596 #?     (write-buffered Stderr " name: ")
30597 #?     50/push-eax
30598 #?     (lookup *eax *(eax+4))  # Var-name
30599 #?     (write-buffered Stderr %eax)
30600 #?     58/pop-to-eax
30601 #?     (write-buffered Stderr Newline)
30602 #?     (flush Stderr)
30603     # return output-var->stack-offset
30604     8b/-> *(eax+0x14) 0/r32/eax  # Var-offset
30605 #?     (write-buffered Stderr "=> ")
30606 #?     (write-int32-hex-buffered Stderr %eax)
30607 #?     (write-buffered Stderr Newline)
30608 #?     (flush Stderr)
30609 $emit-get-offset:end:
30610     # . epilogue
30611     89/<- %esp 5/r32/ebp
30612     5d/pop-to-ebp
30613     c3/return
30615 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)
30616     # . prologue
30617     55/push-ebp
30618     89/<- %ebp 4/r32/esp
30619     # . save registers
30620     50/push-eax
30621     51/push-ecx
30622     56/push-esi
30623     # esi = block
30624     8b/-> *(ebp+0xc) 6/r32/esi
30625     # block->var->block-depth = *Curr-block-depth
30626     (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
30627     8b/-> *Curr-block-depth 1/r32/ecx
30628     89/<- *(eax+0x10) 1/r32/ecx  # Var-block-depth
30629     # var stmts/eax: (addr list stmt) = lookup(block->statements)
30630     (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
30631     #
30632     {
30633 $emit-subx-block:check-empty:
30634       3d/compare-eax-and 0/imm32
30635       0f 84/jump-if-= break/disp32
30636       (emit-indent *(ebp+8) *Curr-block-depth)
30637       (write-buffered *(ebp+8) "{\n")
30638       # var v/ecx: (addr var) = lookup(block->var)
30639       (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
30640       89/<- %ecx 0/r32/eax
30641       #
30642       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
30643       (write-buffered *(ebp+8) %eax)
30644       (write-buffered *(ebp+8) ":loop:\n")
30645       ff 0/subop/increment *Curr-block-depth
30646       (push *(ebp+0x10) *(esi+0xc))  # Block-var
30647       (push *(ebp+0x10) *(esi+0x10))  # Block-var
30648       (push *(ebp+0x10) 0)  # false
30649       # emit block->statements
30650       (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
30651       (emit-subx-stmt-list *(ebp+8) %eax *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
30652       (pop *(ebp+0x10))  # => eax
30653       (pop *(ebp+0x10))  # => eax
30654       (pop *(ebp+0x10))  # => eax
30655       ff 1/subop/decrement *Curr-block-depth
30656       (emit-indent *(ebp+8) *Curr-block-depth)
30657       (write-buffered *(ebp+8) "}\n")
30658       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
30659       (write-buffered *(ebp+8) %eax)
30660       (write-buffered *(ebp+8) ":break:\n")
30661     }
30662 $emit-subx-block:end:
30663     # . restore registers
30664     5e/pop-to-esi
30665     59/pop-to-ecx
30666     58/pop-to-eax
30667     # . epilogue
30668     89/<- %esp 5/r32/ebp
30669     5d/pop-to-ebp
30670     c3/return
30672 # Primitives supported
30673 # See mu_instructions for a summary of this linked-list data structure.
30675 # For each operation, put variants with hard-coded registers before flexible ones.
30677 # Unfortunately, our restrictions on addresses require that various fields in
30678 # primitives be handles, which complicates these definitions.
30679 #   - we need to insert dummy fields all over the place for fake alloc-ids
30680 #   - we can't use our syntax sugar of quoted literals for string fields
30682 # Fake alloc-ids are needed because our type definitions up top require
30683 # handles but it's clearer to statically allocate these long-lived objects.
30684 # Fake alloc-ids are perfectly safe, but they can't be reclaimed.
30686 # Every 'object' below starts with a fake alloc-id. It may also contain other
30687 # fake alloc-ids for various handle fields.
30689 # I think of objects starting with a fake alloc-id as having type 'payload'.
30690 # It's not really intended to be created dynamically; for that use `allocate`
30691 # as usual.
30693 # Idea for a notation to simplify such definitions:
30694 #   _Primitive-increment-eax:  # (payload primitive)
30695 #     0x11/alloc-id:fake:payload
30696 #     0x11 @(0x11 "increment")  # name
30697 #     0 0                       # inouts
30698 #     0x11 @(0x11/payload
30699 #            0x11 @(0x11/payload  # List-value
30700 #                   0 0             # Var-name
30701 #                   0x11 @(0x11     # Var-type
30702 #                          1/is-atom
30703 #                          1/value 0/unused   # Type-tree-left
30704 #                          0 0                # Type-tree-right
30705 #                         )
30706 #                   1               # block-depth
30707 #                   0               # stack-offset
30708 #                   0x11 @(0x11 "eax")  # Var-register
30709 #                  )
30710 #            0 0)                 # List-next
30711 #     ...
30712 #     _Primitive-increment-ecx/imm32/next
30713 #   ...
30714 # Awfully complex and non-obvious. But also clearly signals there's something
30715 # to learn here, so may be worth trying.
30717 # '@' is just an initial thought. Punctuation used so far in Mu: () * % # / "
30719 # For now we'll continue to just use comments and manually ensure they stay up
30720 # to date.
30721 == data
30722 Primitives:  # (addr primitive)
30723 # - increment/decrement
30724 _Primitive-increment-eax:  # (addr primitive)
30725     # var/eax <- increment => 40/increment-eax
30726     0x11/imm32/alloc-id:fake
30727     _string-increment/imm32/name
30728     0/imm32/no-inouts
30729     0/imm32/no-inouts
30730     0x11/imm32/alloc-id:fake
30731     Single-int-var-in-eax/imm32/outputs
30732     0x11/imm32/alloc-id:fake
30733     _string_40_increment_eax/imm32/subx-name
30734     0/imm32/no-rm32
30735     0/imm32/no-r32
30736     0/imm32/no-imm32
30737     0/imm32/no-imm8
30738     0/imm32/no-disp32
30739     0/imm32/no-xm32
30740     0/imm32/no-x32
30741     0x11/imm32/alloc-id:fake
30742     _Primitive-increment-ecx/imm32/next
30743 _Primitive-increment-ecx:  # (payload primitive)
30744     0x11/imm32/alloc-id:fake:payload
30745     # var/ecx <- increment => 41/increment-ecx
30746     0x11/imm32/alloc-id:fake
30747     _string-increment/imm32/name
30748     0/imm32/no-inouts
30749     0/imm32/no-inouts
30750     0x11/imm32/alloc-id:fake
30751     Single-int-var-in-ecx/imm32/outputs
30752     0x11/imm32/alloc-id:fake
30753     _string_41_increment_ecx/imm32/subx-name
30754     0/imm32/no-rm32
30755     0/imm32/no-r32
30756     0/imm32/no-imm32
30757     0/imm32/no-imm8
30758     0/imm32/no-disp32
30759     0/imm32/no-xm32
30760     0/imm32/no-x32
30761     0x11/imm32/alloc-id:fake
30762     _Primitive-increment-edx/imm32/next
30763 _Primitive-increment-edx:  # (payload primitive)
30764     0x11/imm32/alloc-id:fake:payload
30765     # var/edx <- increment => 42/increment-edx
30766     0x11/imm32/alloc-id:fake
30767     _string-increment/imm32/name
30768     0/imm32/no-inouts
30769     0/imm32/no-inouts
30770     0x11/imm32/alloc-id:fake
30771     Single-int-var-in-edx/imm32/outputs
30772     0x11/imm32/alloc-id:fake
30773     _string_42_increment_edx/imm32/subx-name
30774     0/imm32/no-rm32
30775     0/imm32/no-r32
30776     0/imm32/no-imm32
30777     0/imm32/no-imm8
30778     0/imm32/no-disp32
30779     0/imm32/no-xm32
30780     0/imm32/no-x32
30781     0x11/imm32/alloc-id:fake
30782     _Primitive-increment-ebx/imm32/next
30783 _Primitive-increment-ebx:  # (payload primitive)
30784     0x11/imm32/alloc-id:fake:payload
30785     # var/ebx <- increment => 43/increment-ebx
30786     0x11/imm32/alloc-id:fake
30787     _string-increment/imm32/name
30788     0/imm32/no-inouts
30789     0/imm32/no-inouts
30790     0x11/imm32/alloc-id:fake
30791     Single-int-var-in-ebx/imm32/outputs
30792     0x11/imm32/alloc-id:fake
30793     _string_43_increment_ebx/imm32/subx-name
30794     0/imm32/no-rm32
30795     0/imm32/no-r32
30796     0/imm32/no-imm32
30797     0/imm32/no-imm8
30798     0/imm32/no-disp32
30799     0/imm32/no-xm32
30800     0/imm32/no-x32
30801     0x11/imm32/alloc-id:fake
30802     _Primitive-increment-esi/imm32/next
30803 _Primitive-increment-esi:  # (payload primitive)
30804     0x11/imm32/alloc-id:fake:payload
30805     # var/esi <- increment => 46/increment-esi
30806     0x11/imm32/alloc-id:fake
30807     _string-increment/imm32/name
30808     0/imm32/no-inouts
30809     0/imm32/no-inouts
30810     0x11/imm32/alloc-id:fake
30811     Single-int-var-in-esi/imm32/outputs
30812     0x11/imm32/alloc-id:fake
30813     _string_46_increment_esi/imm32/subx-name
30814     0/imm32/no-rm32
30815     0/imm32/no-r32
30816     0/imm32/no-imm32
30817     0/imm32/no-imm8
30818     0/imm32/no-disp32
30819     0/imm32/no-xm32
30820     0/imm32/no-x32
30821     0x11/imm32/alloc-id:fake
30822     _Primitive-increment-edi/imm32/next
30823 _Primitive-increment-edi:  # (payload primitive)
30824     0x11/imm32/alloc-id:fake:payload
30825     # var/edi <- increment => 47/increment-edi
30826     0x11/imm32/alloc-id:fake
30827     _string-increment/imm32/name
30828     0/imm32/no-inouts
30829     0/imm32/no-inouts
30830     0x11/imm32/alloc-id:fake
30831     Single-int-var-in-edi/imm32/outputs
30832     0x11/imm32/alloc-id:fake
30833     _string_47_increment_edi/imm32/subx-name
30834     0/imm32/no-rm32
30835     0/imm32/no-r32
30836     0/imm32/no-imm32
30837     0/imm32/no-imm8
30838     0/imm32/no-disp32
30839     0/imm32/no-xm32
30840     0/imm32/no-x32
30841     0x11/imm32/alloc-id:fake
30842     _Primitive-decrement-eax/imm32/next
30843 _Primitive-decrement-eax:  # (payload primitive)
30844     0x11/imm32/alloc-id:fake:payload
30845     # var/eax <- decrement => 48/decrement-eax
30846     0x11/imm32/alloc-id:fake
30847     _string-decrement/imm32/name
30848     0/imm32/no-inouts
30849     0/imm32/no-inouts
30850     0x11/imm32/alloc-id:fake
30851     Single-int-var-in-eax/imm32/outputs
30852     0x11/imm32/alloc-id:fake
30853     _string_48_decrement_eax/imm32/subx-name
30854     0/imm32/no-rm32
30855     0/imm32/no-r32
30856     0/imm32/no-imm32
30857     0/imm32/no-imm8
30858     0/imm32/no-disp32
30859     0/imm32/no-xm32
30860     0/imm32/no-x32
30861     0x11/imm32/alloc-id:fake
30862     _Primitive-decrement-ecx/imm32/next
30863 _Primitive-decrement-ecx:  # (payload primitive)
30864     0x11/imm32/alloc-id:fake:payload
30865     # var/ecx <- decrement => 49/decrement-ecx
30866     0x11/imm32/alloc-id:fake
30867     _string-decrement/imm32/name
30868     0/imm32/no-inouts
30869     0/imm32/no-inouts
30870     0x11/imm32/alloc-id:fake
30871     Single-int-var-in-ecx/imm32/outputs
30872     0x11/imm32/alloc-id:fake
30873     _string_49_decrement_ecx/imm32/subx-name
30874     0/imm32/no-rm32
30875     0/imm32/no-r32
30876     0/imm32/no-imm32
30877     0/imm32/no-imm8
30878     0/imm32/no-disp32
30879     0/imm32/no-xm32
30880     0/imm32/no-x32
30881     0x11/imm32/alloc-id:fake
30882     _Primitive-decrement-edx/imm32/next
30883 _Primitive-decrement-edx:  # (payload primitive)
30884     0x11/imm32/alloc-id:fake:payload
30885     # var/edx <- decrement => 4a/decrement-edx
30886     0x11/imm32/alloc-id:fake
30887     _string-decrement/imm32/name
30888     0/imm32/no-inouts
30889     0/imm32/no-inouts
30890     0x11/imm32/alloc-id:fake
30891     Single-int-var-in-edx/imm32/outputs
30892     0x11/imm32/alloc-id:fake
30893     _string_4a_decrement_edx/imm32/subx-name
30894     0/imm32/no-rm32
30895     0/imm32/no-r32
30896     0/imm32/no-imm32
30897     0/imm32/no-imm8
30898     0/imm32/no-disp32
30899     0/imm32/no-xm32
30900     0/imm32/no-x32
30901     0x11/imm32/alloc-id:fake
30902     _Primitive-decrement-ebx/imm32/next
30903 _Primitive-decrement-ebx:  # (payload primitive)
30904     0x11/imm32/alloc-id:fake:payload
30905     # var/ebx <- decrement => 4b/decrement-ebx
30906     0x11/imm32/alloc-id:fake
30907     _string-decrement/imm32/name
30908     0/imm32/no-inouts
30909     0/imm32/no-inouts
30910     0x11/imm32/alloc-id:fake
30911     Single-int-var-in-ebx/imm32/outputs
30912     0x11/imm32/alloc-id:fake
30913     _string_4b_decrement_ebx/imm32/subx-name
30914     0/imm32/no-rm32
30915     0/imm32/no-r32
30916     0/imm32/no-imm32
30917     0/imm32/no-imm8
30918     0/imm32/no-disp32
30919     0/imm32/no-xm32
30920     0/imm32/no-x32
30921     0x11/imm32/alloc-id:fake
30922     _Primitive-decrement-esi/imm32/next
30923 _Primitive-decrement-esi:  # (payload primitive)
30924     0x11/imm32/alloc-id:fake:payload
30925     # var/esi <- decrement => 4e/decrement-esi
30926     0x11/imm32/alloc-id:fake
30927     _string-decrement/imm32/name
30928     0/imm32/no-inouts
30929     0/imm32/no-inouts
30930     0x11/imm32/alloc-id:fake
30931     Single-int-var-in-esi/imm32/outputs
30932     0x11/imm32/alloc-id:fake
30933     _string_4e_decrement_esi/imm32/subx-name
30934     0/imm32/no-rm32
30935     0/imm32/no-r32
30936     0/imm32/no-imm32
30937     0/imm32/no-imm8
30938     0/imm32/no-disp32
30939     0/imm32/no-xm32
30940     0/imm32/no-x32
30941     0x11/imm32/alloc-id:fake
30942     _Primitive-decrement-edi/imm32/next
30943 _Primitive-decrement-edi:  # (payload primitive)
30944     0x11/imm32/alloc-id:fake:payload
30945     # var/edi <- decrement => 4f/decrement-edi
30946     0x11/imm32/alloc-id:fake
30947     _string-decrement/imm32/name
30948     0/imm32/no-inouts
30949     0/imm32/no-inouts
30950     0x11/imm32/alloc-id:fake
30951     Single-int-var-in-edi/imm32/outputs
30952     0x11/imm32/alloc-id:fake
30953     _string_4f_decrement_edi/imm32/subx-name
30954     0/imm32/no-rm32
30955     0/imm32/no-r32
30956     0/imm32/no-imm32
30957     0/imm32/no-imm8
30958     0/imm32/no-disp32
30959     0/imm32/no-xm32
30960     0/imm32/no-x32
30961     0x11/imm32/alloc-id:fake
30962     _Primitive-increment-mem/imm32/next
30963 _Primitive-increment-mem:  # (payload primitive)
30964     0x11/imm32/alloc-id:fake:payload
30965     # increment var => ff 0/subop/increment *(ebp+__)
30966     0x11/imm32/alloc-id:fake
30967     _string-increment/imm32/name
30968     0x11/imm32/alloc-id:fake
30969     Single-int-var-in-mem/imm32/inouts
30970     0/imm32/no-outputs
30971     0/imm32/no-outputs
30972     0x11/imm32/alloc-id:fake
30973     _string_ff_subop_increment/imm32/subx-name
30974     1/imm32/rm32-is-first-inout
30975     0/imm32/no-r32
30976     0/imm32/no-imm32
30977     0/imm32/no-imm8
30978     0/imm32/no-disp32
30979     0/imm32/no-xm32
30980     0/imm32/no-x32
30981     0x11/imm32/alloc-id:fake
30982     _Primitive-increment-reg/imm32/next
30983 _Primitive-increment-reg:  # (payload primitive)
30984     0x11/imm32/alloc-id:fake:payload
30985     # var/reg <- increment => ff 0/subop/increment %__
30986     0x11/imm32/alloc-id:fake
30987     _string-increment/imm32/name
30988     0/imm32/no-inouts
30989     0/imm32/no-inouts
30990     0x11/imm32/alloc-id:fake
30991     Single-int-var-in-some-register/imm32/outputs
30992     0x11/imm32/alloc-id:fake
30993     _string_ff_subop_increment/imm32/subx-name
30994     3/imm32/rm32-is-first-output
30995     0/imm32/no-r32
30996     0/imm32/no-imm32
30997     0/imm32/no-imm8
30998     0/imm32/no-disp32
30999     0/imm32/no-xm32
31000     0/imm32/no-x32
31001     0x11/imm32/alloc-id:fake
31002     _Primitive-decrement-mem/imm32/next
31003 _Primitive-decrement-mem:  # (payload primitive)
31004     0x11/imm32/alloc-id:fake:payload
31005     # decrement var => ff 1/subop/decrement *(ebp+__)
31006     0x11/imm32/alloc-id:fake
31007     _string-decrement/imm32/name
31008     0x11/imm32/alloc-id:fake
31009     Single-int-var-in-mem/imm32/inouts
31010     0/imm32/no-outputs
31011     0/imm32/no-outputs
31012     0x11/imm32/alloc-id:fake
31013     _string_ff_subop_decrement/imm32/subx-name
31014     1/imm32/rm32-is-first-inout
31015     0/imm32/no-r32
31016     0/imm32/no-imm32
31017     0/imm32/no-imm8
31018     0/imm32/no-disp32
31019     0/imm32/no-xm32
31020     0/imm32/no-x32
31021     0x11/imm32/alloc-id:fake
31022     _Primitive-decrement-reg/imm32/next
31023 _Primitive-decrement-reg:  # (payload primitive)
31024     0x11/imm32/alloc-id:fake:payload
31025     # var/reg <- decrement => ff 1/subop/decrement %__
31026     0x11/imm32/alloc-id:fake
31027     _string-decrement/imm32/name
31028     0/imm32/no-inouts
31029     0/imm32/no-inouts
31030     0x11/imm32/alloc-id:fake
31031     Single-int-var-in-some-register/imm32/outputs
31032     0x11/imm32/alloc-id:fake
31033     _string_ff_subop_decrement/imm32/subx-name
31034     3/imm32/rm32-is-first-output
31035     0/imm32/no-r32
31036     0/imm32/no-imm32
31037     0/imm32/no-imm8
31038     0/imm32/no-disp32
31039     0/imm32/no-xm32
31040     0/imm32/no-x32
31041     0x11/imm32/alloc-id:fake
31042     _Primitive-add-to-eax/imm32/next
31043 # - add
31044 _Primitive-add-to-eax:  # (payload primitive)
31045     0x11/imm32/alloc-id:fake:payload
31046     # var/eax <- add lit => 05/add-to-eax lit/imm32
31047     0x11/imm32/alloc-id:fake
31048     _string-add/imm32/name
31049     0x11/imm32/alloc-id:fake
31050     Single-lit-var/imm32/inouts
31051     0x11/imm32/alloc-id:fake
31052     Single-int-var-in-eax/imm32/outputs
31053     0x11/imm32/alloc-id:fake
31054     _string_05_add_to_eax/imm32/subx-name
31055     0/imm32/no-rm32
31056     0/imm32/no-r32
31057     1/imm32/imm32-is-first-inout
31058     0/imm32/no-imm8
31059     0/imm32/no-disp32
31060     0/imm32/no-xm32
31061     0/imm32/no-x32
31062     0x11/imm32/alloc-id:fake
31063     _Primitive-add-reg-to-reg/imm32/next
31064 _Primitive-add-reg-to-reg:  # (payload primitive)
31065     0x11/imm32/alloc-id:fake:payload
31066     # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32
31067     0x11/imm32/alloc-id:fake
31068     _string-add/imm32/name
31069     0x11/imm32/alloc-id:fake
31070     Single-int-var-in-some-register/imm32/inouts
31071     0x11/imm32/alloc-id:fake
31072     Single-int-var-in-some-register/imm32/outputs
31073     0x11/imm32/alloc-id:fake
31074     _string_01_add_to/imm32/subx-name
31075     3/imm32/rm32-is-first-output
31076     1/imm32/r32-is-first-inout
31077     0/imm32/no-imm32
31078     0/imm32/no-imm8
31079     0/imm32/no-disp32
31080     0/imm32/no-xm32
31081     0/imm32/no-x32
31082     0x11/imm32/alloc-id:fake
31083     _Primitive-add-reg-to-mem/imm32/next
31084 _Primitive-add-reg-to-mem:  # (payload primitive)
31085     0x11/imm32/alloc-id:fake:payload
31086     # add-to var1 var2/reg => 01/add-to var1 var2/r32
31087     0x11/imm32/alloc-id:fake
31088     _string-add-to/imm32/name
31089     0x11/imm32/alloc-id:fake
31090     Two-args-int-stack-int-reg/imm32/inouts
31091     0/imm32/no-outputs
31092     0/imm32/no-outputs
31093     0x11/imm32/alloc-id:fake
31094     _string_01_add_to/imm32/subx-name
31095     1/imm32/rm32-is-first-inout
31096     2/imm32/r32-is-second-inout
31097     0/imm32/no-imm32
31098     0/imm32/no-imm8
31099     0/imm32/no-disp32
31100     0/imm32/no-xm32
31101     0/imm32/no-x32
31102     0x11/imm32/alloc-id:fake
31103     _Primitive-add-mem-to-reg/imm32/next
31104 _Primitive-add-mem-to-reg:  # (payload primitive)
31105     0x11/imm32/alloc-id:fake:payload
31106     # var1/reg <- add var2 => 03/add var2/rm32 var1/r32
31107     0x11/imm32/alloc-id:fake
31108     _string-add/imm32/name
31109     0x11/imm32/alloc-id:fake
31110     Single-int-var-in-mem/imm32/inouts
31111     0x11/imm32/alloc-id:fake
31112     Single-int-var-in-some-register/imm32/outputs
31113     0x11/imm32/alloc-id:fake
31114     _string_03_add/imm32/subx-name
31115     1/imm32/rm32-is-first-inout
31116     3/imm32/r32-is-first-output
31117     0/imm32/no-imm32
31118     0/imm32/no-imm8
31119     0/imm32/no-disp32
31120     0/imm32/no-xm32
31121     0/imm32/no-x32
31122     0x11/imm32/alloc-id:fake
31123     _Primitive-add-lit-to-reg/imm32/next
31124 _Primitive-add-lit-to-reg:  # (payload primitive)
31125     0x11/imm32/alloc-id:fake:payload
31126     # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32
31127     0x11/imm32/alloc-id:fake
31128     _string-add/imm32/name
31129     0x11/imm32/alloc-id:fake
31130     Single-lit-var/imm32/inouts
31131     0x11/imm32/alloc-id:fake
31132     Single-int-var-in-some-register/imm32/outputs
31133     0x11/imm32/alloc-id:fake
31134     _string_81_subop_add/imm32/subx-name
31135     3/imm32/rm32-is-first-output
31136     0/imm32/no-r32
31137     1/imm32/imm32-is-first-inout
31138     0/imm32/no-imm8
31139     0/imm32/no-disp32
31140     0/imm32/no-xm32
31141     0/imm32/no-x32
31142     0x11/imm32/alloc-id:fake
31143     _Primitive-add-lit-to-mem/imm32/next
31144 _Primitive-add-lit-to-mem:  # (payload primitive)
31145     0x11/imm32/alloc-id:fake:payload
31146     # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32
31147     0x11/imm32/alloc-id:fake
31148     _string-add-to/imm32/name
31149     0x11/imm32/alloc-id:fake
31150     Int-var-and-literal/imm32/inouts
31151     0/imm32/no-outputs
31152     0/imm32/no-outputs
31153     0x11/imm32/alloc-id:fake
31154     _string_81_subop_add/imm32/subx-name
31155     1/imm32/rm32-is-first-inout
31156     0/imm32/no-r32
31157     2/imm32/imm32-is-second-inout
31158     0/imm32/no-imm8
31159     0/imm32/no-disp32
31160     0/imm32/no-xm32
31161     0/imm32/no-x32
31162     0x11/imm32/alloc-id:fake
31163     _Primitive-subtract-from-eax/imm32/next
31164 # - subtract
31165 _Primitive-subtract-from-eax:  # (payload primitive)
31166     0x11/imm32/alloc-id:fake:payload
31167     # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32
31168     0x11/imm32/alloc-id:fake
31169     _string-subtract/imm32/name
31170     0x11/imm32/alloc-id:fake
31171     Single-lit-var/imm32/inouts
31172     0x11/imm32/alloc-id:fake
31173     Single-int-var-in-eax/imm32/outputs
31174     0x11/imm32/alloc-id:fake
31175     _string_2d_subtract_from_eax/imm32/subx-name
31176     0/imm32/no-rm32
31177     0/imm32/no-r32
31178     1/imm32/imm32-is-first-inout
31179     0/imm32/no-imm8
31180     0/imm32/no-disp32
31181     0/imm32/no-xm32
31182     0/imm32/no-x32
31183     0x11/imm32/alloc-id:fake
31184     _Primitive-subtract-reg-from-reg/imm32/next
31185 _Primitive-subtract-reg-from-reg:  # (payload primitive)
31186     0x11/imm32/alloc-id:fake:payload
31187     # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32
31188     0x11/imm32/alloc-id:fake
31189     _string-subtract/imm32/name
31190     0x11/imm32/alloc-id:fake
31191     Single-int-var-in-some-register/imm32/inouts
31192     0x11/imm32/alloc-id:fake
31193     Single-int-var-in-some-register/imm32/outputs
31194     0x11/imm32/alloc-id:fake
31195     _string_29_subtract_from/imm32/subx-name
31196     3/imm32/rm32-is-first-output
31197     1/imm32/r32-is-first-inout
31198     0/imm32/no-imm32
31199     0/imm32/no-imm8
31200     0/imm32/no-disp32
31201     0/imm32/no-xm32
31202     0/imm32/no-x32
31203     0x11/imm32/alloc-id:fake
31204     _Primitive-subtract-reg-from-mem/imm32/next
31205 _Primitive-subtract-reg-from-mem:  # (payload primitive)
31206     0x11/imm32/alloc-id:fake:payload
31207     # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32
31208     0x11/imm32/alloc-id:fake
31209     _string-subtract-from/imm32/name
31210     0x11/imm32/alloc-id:fake
31211     Two-args-int-stack-int-reg/imm32/inouts
31212     0/imm32/no-outputs
31213     0/imm32/no-outputs
31214     0x11/imm32/alloc-id:fake
31215     _string_29_subtract_from/imm32/subx-name
31216     1/imm32/rm32-is-first-inout
31217     2/imm32/r32-is-second-inout
31218     0/imm32/no-imm32
31219     0/imm32/no-imm8
31220     0/imm32/no-disp32
31221     0/imm32/no-xm32
31222     0/imm32/no-x32
31223     0x11/imm32/alloc-id:fake
31224     _Primitive-subtract-mem-from-reg/imm32/next
31225 _Primitive-subtract-mem-from-reg:  # (payload primitive)
31226     0x11/imm32/alloc-id:fake:payload
31227     # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32
31228     0x11/imm32/alloc-id:fake
31229     _string-subtract/imm32/name
31230     0x11/imm32/alloc-id:fake
31231     Single-int-var-in-mem/imm32/inouts
31232     0x11/imm32/alloc-id:fake
31233     Single-int-var-in-some-register/imm32/outputs
31234     0x11/imm32/alloc-id:fake
31235     _string_2b_subtract/imm32/subx-name
31236     1/imm32/rm32-is-first-inout
31237     3/imm32/r32-is-first-output
31238     0/imm32/no-imm32
31239     0/imm32/no-imm8
31240     0/imm32/no-disp32
31241     0/imm32/no-xm32
31242     0/imm32/no-x32
31243     0x11/imm32/alloc-id:fake
31244     _Primitive-subtract-lit-from-reg/imm32/next
31245 _Primitive-subtract-lit-from-reg:  # (payload primitive)
31246     0x11/imm32/alloc-id:fake:payload
31247     # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32
31248     0x11/imm32/alloc-id:fake
31249     _string-subtract/imm32/name
31250     0x11/imm32/alloc-id:fake
31251     Single-lit-var/imm32/inouts
31252     0x11/imm32/alloc-id:fake
31253     Single-int-var-in-some-register/imm32/outputs
31254     0x11/imm32/alloc-id:fake
31255     _string_81_subop_subtract/imm32/subx-name
31256     3/imm32/rm32-is-first-output
31257     0/imm32/no-r32
31258     1/imm32/imm32-is-first-inout
31259     0/imm32/no-imm8
31260     0/imm32/no-disp32
31261     0/imm32/no-xm32
31262     0/imm32/no-x32
31263     0x11/imm32/alloc-id:fake
31264     _Primitive-subtract-lit-from-mem/imm32/next
31265 _Primitive-subtract-lit-from-mem:  # (payload primitive)
31266     0x11/imm32/alloc-id:fake:payload
31267     # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32
31268     0x11/imm32/alloc-id:fake
31269     _string-subtract-from/imm32/name
31270     0x11/imm32/alloc-id:fake
31271     Int-var-and-literal/imm32/inouts
31272     0/imm32/no-outputs
31273     0/imm32/no-outputs
31274     0x11/imm32/alloc-id:fake
31275     _string_81_subop_subtract/imm32/subx-name
31276     1/imm32/rm32-is-first-inout
31277     0/imm32/no-r32
31278     2/imm32/imm32-is-second-inout
31279     0/imm32/no-imm8
31280     0/imm32/no-disp32
31281     0/imm32/no-xm32
31282     0/imm32/no-x32
31283     0x11/imm32/alloc-id:fake
31284     _Primitive-and-with-eax/imm32/next
31285 # - and
31286 _Primitive-and-with-eax:  # (payload primitive)
31287     0x11/imm32/alloc-id:fake:payload
31288     # var/eax <- and lit => 25/and-with-eax lit/imm32
31289     0x11/imm32/alloc-id:fake
31290     _string-and/imm32/name
31291     0x11/imm32/alloc-id:fake
31292     Single-lit-var/imm32/inouts
31293     0x11/imm32/alloc-id:fake
31294     Single-int-var-in-eax/imm32/outputs
31295     0x11/imm32/alloc-id:fake
31296     _string_25_and_with_eax/imm32/subx-name
31297     0/imm32/no-rm32
31298     0/imm32/no-r32
31299     1/imm32/imm32-is-first-inout
31300     0/imm32/no-imm8
31301     0/imm32/no-disp32
31302     0/imm32/no-xm32
31303     0/imm32/no-x32
31304     0x11/imm32/alloc-id:fake
31305     _Primitive-and-reg-with-reg/imm32/next
31306 _Primitive-and-reg-with-reg:  # (payload primitive)
31307     0x11/imm32/alloc-id:fake:payload
31308     # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32
31309     0x11/imm32/alloc-id:fake
31310     _string-and/imm32/name
31311     0x11/imm32/alloc-id:fake
31312     Single-int-var-in-some-register/imm32/inouts
31313     0x11/imm32/alloc-id:fake
31314     Single-int-var-in-some-register/imm32/outputs
31315     0x11/imm32/alloc-id:fake
31316     _string_21_and_with/imm32/subx-name
31317     3/imm32/rm32-is-first-output
31318     1/imm32/r32-is-first-inout
31319     0/imm32/no-imm32
31320     0/imm32/no-imm8
31321     0/imm32/no-disp32
31322     0/imm32/no-xm32
31323     0/imm32/no-x32
31324     0x11/imm32/alloc-id:fake
31325     _Primitive-and-reg-with-mem/imm32/next
31326 _Primitive-and-reg-with-mem:  # (payload primitive)
31327     0x11/imm32/alloc-id:fake:payload
31328     # and-with var1 var2/reg => 21/and-with var1 var2/r32
31329     0x11/imm32/alloc-id:fake
31330     _string-and-with/imm32/name
31331     0x11/imm32/alloc-id:fake
31332     Two-args-int-stack-int-reg/imm32/inouts
31333     0/imm32/no-outputs
31334     0/imm32/no-outputs
31335     0x11/imm32/alloc-id:fake
31336     _string_21_and_with/imm32/subx-name
31337     1/imm32/rm32-is-first-inout
31338     2/imm32/r32-is-second-inout
31339     0/imm32/no-imm32
31340     0/imm32/no-imm8
31341     0/imm32/no-disp32
31342     0/imm32/no-xm32
31343     0/imm32/no-x32
31344     0x11/imm32/alloc-id:fake
31345     _Primitive-and-mem-with-reg/imm32/next
31346 _Primitive-and-mem-with-reg:  # (payload primitive)
31347     0x11/imm32/alloc-id:fake:payload
31348     # var1/reg <- and var2 => 23/and var2/rm32 var1/r32
31349     0x11/imm32/alloc-id:fake
31350     _string-and/imm32/name
31351     0x11/imm32/alloc-id:fake
31352     Single-int-var-in-mem/imm32/inouts
31353     0x11/imm32/alloc-id:fake
31354     Single-int-var-in-some-register/imm32/outputs
31355     0x11/imm32/alloc-id:fake
31356     _string_23_and/imm32/subx-name
31357     1/imm32/rm32-is-first-inout
31358     3/imm32/r32-is-first-output
31359     0/imm32/no-imm32
31360     0/imm32/no-imm8
31361     0/imm32/no-disp32
31362     0/imm32/no-xm32
31363     0/imm32/no-x32
31364     0x11/imm32/alloc-id:fake
31365     _Primitive-and-lit-with-reg/imm32/next
31366 _Primitive-and-lit-with-reg:  # (payload primitive)
31367     0x11/imm32/alloc-id:fake:payload
31368     # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32
31369     0x11/imm32/alloc-id:fake
31370     _string-and/imm32/name
31371     0x11/imm32/alloc-id:fake
31372     Single-lit-var/imm32/inouts
31373     0x11/imm32/alloc-id:fake
31374     Single-int-var-in-some-register/imm32/outputs
31375     0x11/imm32/alloc-id:fake
31376     _string_81_subop_and/imm32/subx-name
31377     3/imm32/rm32-is-first-output
31378     0/imm32/no-r32
31379     1/imm32/imm32-is-first-inout
31380     0/imm32/no-imm8
31381     0/imm32/no-disp32
31382     0/imm32/no-xm32
31383     0/imm32/no-x32
31384     0x11/imm32/alloc-id:fake
31385     _Primitive-and-lit-with-mem/imm32/next
31386 _Primitive-and-lit-with-mem:  # (payload primitive)
31387     0x11/imm32/alloc-id:fake:payload
31388     # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32
31389     0x11/imm32/alloc-id:fake
31390     _string-and-with/imm32/name
31391     0x11/imm32/alloc-id:fake
31392     Int-var-and-literal/imm32/inouts
31393     0/imm32/no-outputs
31394     0/imm32/no-outputs
31395     0x11/imm32/alloc-id:fake
31396     _string_81_subop_and/imm32/subx-name
31397     1/imm32/rm32-is-first-inout
31398     0/imm32/no-r32
31399     2/imm32/imm32-is-second-inout
31400     0/imm32/no-imm8
31401     0/imm32/no-disp32
31402     0/imm32/no-xm32
31403     0/imm32/no-x32
31404     0x11/imm32/alloc-id:fake
31405     _Primitive-or-with-eax/imm32/next
31406 # - or
31407 _Primitive-or-with-eax:  # (payload primitive)
31408     0x11/imm32/alloc-id:fake:payload
31409     # var/eax <- or lit => 0d/or-with-eax lit/imm32
31410     0x11/imm32/alloc-id:fake
31411     _string-or/imm32/name
31412     0x11/imm32/alloc-id:fake
31413     Single-lit-var/imm32/inouts
31414     0x11/imm32/alloc-id:fake
31415     Single-int-var-in-eax/imm32/outputs
31416     0x11/imm32/alloc-id:fake
31417     _string_0d_or_with_eax/imm32/subx-name
31418     0/imm32/no-rm32
31419     0/imm32/no-r32
31420     1/imm32/imm32-is-first-inout
31421     0/imm32/no-imm8
31422     0/imm32/no-disp32
31423     0/imm32/no-xm32
31424     0/imm32/no-x32
31425     0x11/imm32/alloc-id:fake
31426     _Primitive-or-reg-with-reg/imm32/next
31427 _Primitive-or-reg-with-reg:  # (payload primitive)
31428     0x11/imm32/alloc-id:fake:payload
31429     # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32
31430     0x11/imm32/alloc-id:fake
31431     _string-or/imm32/name
31432     0x11/imm32/alloc-id:fake
31433     Single-int-var-in-some-register/imm32/inouts
31434     0x11/imm32/alloc-id:fake
31435     Single-int-var-in-some-register/imm32/outputs
31436     0x11/imm32/alloc-id:fake
31437     _string_09_or_with/imm32/subx-name
31438     3/imm32/rm32-is-first-output
31439     1/imm32/r32-is-first-inout
31440     0/imm32/no-imm32
31441     0/imm32/no-imm8
31442     0/imm32/no-disp32
31443     0/imm32/no-xm32
31444     0/imm32/no-x32
31445     0x11/imm32/alloc-id:fake
31446     _Primitive-or-reg-with-mem/imm32/next
31447 _Primitive-or-reg-with-mem:  # (payload primitive)
31448     0x11/imm32/alloc-id:fake:payload
31449     # or-with var1 var2/reg => 09/or-with var1 var2/r32
31450     0x11/imm32/alloc-id:fake
31451     _string-or-with/imm32/name
31452     0x11/imm32/alloc-id:fake
31453     Two-args-int-stack-int-reg/imm32/inouts
31454     0/imm32/no-outputs
31455     0/imm32/no-outputs
31456     0x11/imm32/alloc-id:fake
31457     _string_09_or_with/imm32/subx-name
31458     1/imm32/rm32-is-first-inout
31459     2/imm32/r32-is-second-inout
31460     0/imm32/no-imm32
31461     0/imm32/no-imm8
31462     0/imm32/no-disp32
31463     0/imm32/no-xm32
31464     0/imm32/no-x32
31465     0x11/imm32/alloc-id:fake
31466     _Primitive-or-mem-with-reg/imm32/next
31467 _Primitive-or-mem-with-reg:  # (payload primitive)
31468     0x11/imm32/alloc-id:fake:payload
31469     # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32
31470     0x11/imm32/alloc-id:fake
31471     _string-or/imm32/name
31472     0x11/imm32/alloc-id:fake
31473     Single-int-var-in-mem/imm32/inouts
31474     0x11/imm32/alloc-id:fake
31475     Single-int-var-in-some-register/imm32/outputs
31476     0x11/imm32/alloc-id:fake
31477     _string_0b_or/imm32/subx-name
31478     1/imm32/rm32-is-first-inout
31479     3/imm32/r32-is-first-output
31480     0/imm32/no-imm32
31481     0/imm32/no-imm8
31482     0/imm32/no-disp32
31483     0/imm32/no-xm32
31484     0/imm32/no-x32
31485     0x11/imm32/alloc-id:fake
31486     _Primitive-or-lit-with-reg/imm32/next
31487 _Primitive-or-lit-with-reg:  # (payload primitive)
31488     0x11/imm32/alloc-id:fake:payload
31489     # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32
31490     0x11/imm32/alloc-id:fake
31491     _string-or/imm32/name
31492     0x11/imm32/alloc-id:fake
31493     Single-lit-var/imm32/inouts
31494     0x11/imm32/alloc-id:fake
31495     Single-int-var-in-some-register/imm32/outputs
31496     0x11/imm32/alloc-id:fake
31497     _string_81_subop_or/imm32/subx-name
31498     3/imm32/rm32-is-first-output
31499     0/imm32/no-r32
31500     1/imm32/imm32-is-first-inout
31501     0/imm32/no-imm8
31502     0/imm32/no-disp32
31503     0/imm32/no-xm32
31504     0/imm32/no-x32
31505     0x11/imm32/alloc-id:fake
31506     _Primitive-or-lit-with-mem/imm32/next
31507 _Primitive-or-lit-with-mem:  # (payload primitive)
31508     0x11/imm32/alloc-id:fake:payload
31509     # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32
31510     0x11/imm32/alloc-id:fake
31511     _string-or-with/imm32/name
31512     0x11/imm32/alloc-id:fake
31513     Int-var-and-literal/imm32/inouts
31514     0/imm32/no-outputs
31515     0/imm32/no-outputs
31516     0x11/imm32/alloc-id:fake
31517     _string_81_subop_or/imm32/subx-name
31518     1/imm32/rm32-is-first-inout
31519     0/imm32/no-r32
31520     2/imm32/imm32-is-second-inout
31521     0/imm32/no-imm8
31522     0/imm32/no-disp32
31523     0/imm32/no-xm32
31524     0/imm32/no-x32
31525     0x11/imm32/alloc-id:fake
31526     _Primitive-not-reg/imm32/next
31527 # - not
31528 _Primitive-not-reg:  # (payload primitive)
31529     0x11/imm32/alloc-id:fake:payload
31530     # var1/reg <- not => f7 2/subop/not var1/rm32
31531     0x11/imm32/alloc-id:fake
31532     _string-not/imm32/name
31533     0/imm32/no-inouts
31534     0/imm32/no-inouts
31535     0x11/imm32/alloc-id:fake
31536     Single-int-var-in-some-register/imm32/outputs
31537     0x11/imm32/alloc-id:fake
31538     _string_f7_subop_not/imm32/subx-name
31539     3/imm32/rm32-is-first-output
31540     0/imm32/no-r32
31541     0/imm32/no-imm32
31542     0/imm32/no-imm8
31543     0/imm32/no-disp32
31544     0/imm32/no-xm32
31545     0/imm32/no-x32
31546     0x11/imm32/alloc-id:fake
31547     _Primitive-not-mem/imm32/next
31548 _Primitive-not-mem:  # (payload primitive)
31549     0x11/imm32/alloc-id:fake:payload
31550     # not var1 => f7 2/subop/not var1/rm32
31551     0x11/imm32/alloc-id:fake
31552     _string-not/imm32/name
31553     0x11/imm32/alloc-id:fake
31554     Single-int-var-in-mem/imm32/inouts
31555     0/imm32/no-outputs
31556     0/imm32/no-outputs
31557     0x11/imm32/alloc-id:fake
31558     _string_f7_subop_not/imm32/subx-name
31559     1/imm32/rm32-is-first-inout
31560     0/imm32/no-r32
31561     0/imm32/no-imm32
31562     0/imm32/no-imm8
31563     0/imm32/no-disp32
31564     0/imm32/no-xm32
31565     0/imm32/no-x32
31566     0x11/imm32/alloc-id:fake
31567     _Primitive-xor-with-eax/imm32/next
31568 # - xor
31569 _Primitive-xor-with-eax:  # (payload primitive)
31570     0x11/imm32/alloc-id:fake:payload
31571     # var/eax <- xor lit => 35/xor-with-eax lit/imm32
31572     0x11/imm32/alloc-id:fake
31573     _string-xor/imm32/name
31574     0x11/imm32/alloc-id:fake
31575     Single-lit-var/imm32/inouts
31576     0x11/imm32/alloc-id:fake
31577     Single-int-var-in-eax/imm32/outputs
31578     0x11/imm32/alloc-id:fake
31579     _string_35_xor_with_eax/imm32/subx-name
31580     0/imm32/no-rm32
31581     0/imm32/no-r32
31582     1/imm32/imm32-is-first-inout
31583     0/imm32/no-imm8
31584     0/imm32/no-disp32
31585     0/imm32/no-xm32
31586     0/imm32/no-x32
31587     0x11/imm32/alloc-id:fake
31588     _Primitive-xor-reg-with-reg/imm32/next
31589 _Primitive-xor-reg-with-reg:  # (payload primitive)
31590     0x11/imm32/alloc-id:fake:payload
31591     # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32
31592     0x11/imm32/alloc-id:fake
31593     _string-xor/imm32/name
31594     0x11/imm32/alloc-id:fake
31595     Single-int-var-in-some-register/imm32/inouts
31596     0x11/imm32/alloc-id:fake
31597     Single-int-var-in-some-register/imm32/outputs
31598     0x11/imm32/alloc-id:fake
31599     _string_31_xor_with/imm32/subx-name
31600     3/imm32/rm32-is-first-output
31601     1/imm32/r32-is-first-inout
31602     0/imm32/no-imm32
31603     0/imm32/no-imm8
31604     0/imm32/no-disp32
31605     0/imm32/no-xm32
31606     0/imm32/no-x32
31607     0x11/imm32/alloc-id:fake
31608     _Primitive-xor-reg-with-mem/imm32/next
31609 _Primitive-xor-reg-with-mem:  # (payload primitive)
31610     0x11/imm32/alloc-id:fake:payload
31611     # xor-with var1 var2/reg => 31/xor-with var1 var2/r32
31612     0x11/imm32/alloc-id:fake
31613     _string-xor-with/imm32/name
31614     0x11/imm32/alloc-id:fake
31615     Two-args-int-stack-int-reg/imm32/inouts
31616     0/imm32/no-outputs
31617     0/imm32/no-outputs
31618     0x11/imm32/alloc-id:fake
31619     _string_31_xor_with/imm32/subx-name
31620     1/imm32/rm32-is-first-inout
31621     2/imm32/r32-is-second-inout
31622     0/imm32/no-imm32
31623     0/imm32/no-imm8
31624     0/imm32/no-disp32
31625     0/imm32/no-xm32
31626     0/imm32/no-x32
31627     0x11/imm32/alloc-id:fake
31628     _Primitive-xor-mem-with-reg/imm32/next
31629 _Primitive-xor-mem-with-reg:  # (payload primitive)
31630     0x11/imm32/alloc-id:fake:payload
31631     # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32
31632     0x11/imm32/alloc-id:fake
31633     _string-xor/imm32/name
31634     0x11/imm32/alloc-id:fake
31635     Single-int-var-in-mem/imm32/inouts
31636     0x11/imm32/alloc-id:fake
31637     Single-int-var-in-some-register/imm32/outputs
31638     0x11/imm32/alloc-id:fake
31639     _string_33_xor/imm32/subx-name
31640     1/imm32/rm32-is-first-inout
31641     3/imm32/r32-is-first-output
31642     0/imm32/no-imm32
31643     0/imm32/no-imm8
31644     0/imm32/no-disp32
31645     0/imm32/no-xm32
31646     0/imm32/no-x32
31647     0x11/imm32/alloc-id:fake
31648     _Primitive-xor-lit-with-reg/imm32/next
31649 _Primitive-xor-lit-with-reg:  # (payload primitive)
31650     0x11/imm32/alloc-id:fake:payload
31651     # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32
31652     0x11/imm32/alloc-id:fake
31653     _string-xor/imm32/name
31654     0x11/imm32/alloc-id:fake
31655     Single-lit-var/imm32/inouts
31656     0x11/imm32/alloc-id:fake
31657     Single-int-var-in-some-register/imm32/outputs
31658     0x11/imm32/alloc-id:fake
31659     _string_81_subop_xor/imm32/subx-name
31660     3/imm32/rm32-is-first-output
31661     0/imm32/no-r32
31662     1/imm32/imm32-is-first-inout
31663     0/imm32/no-imm8
31664     0/imm32/no-disp32
31665     0/imm32/no-xm32
31666     0/imm32/no-x32
31667     0x11/imm32/alloc-id:fake
31668     _Primitive-xor-lit-with-mem/imm32/next
31669 _Primitive-xor-lit-with-mem:  # (payload primitive)
31670     0x11/imm32/alloc-id:fake:payload
31671     # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32
31672     0x11/imm32/alloc-id:fake
31673     _string-xor-with/imm32/name
31674     0x11/imm32/alloc-id:fake
31675     Int-var-and-literal/imm32/inouts
31676     0/imm32/no-outputs
31677     0/imm32/no-outputs
31678     0x11/imm32/alloc-id:fake
31679     _string_81_subop_xor/imm32/subx-name
31680     1/imm32/rm32-is-first-inout
31681     0/imm32/no-r32
31682     2/imm32/imm32-is-second-inout
31683     0/imm32/no-imm8
31684     0/imm32/no-disp32
31685     0/imm32/no-xm32
31686     0/imm32/no-x32
31687     0x11/imm32/alloc-id:fake
31688     _Primitive-shift-reg-left-by-lit/imm32/next
31689 _Primitive-shift-reg-left-by-lit:  # (payload primitive)
31690     0x11/imm32/alloc-id:fake:payload
31691     # var1/reg <- shift-left lit => c1/shift 4/subop/left var1/rm32 lit/imm32
31692     0x11/imm32/alloc-id:fake
31693     _string-shift-left/imm32/name
31694     0x11/imm32/alloc-id:fake
31695     Single-lit-var/imm32/inouts
31696     0x11/imm32/alloc-id:fake
31697     Single-int-var-in-some-register/imm32/outputs
31698     0x11/imm32/alloc-id:fake
31699     _string_c1_subop_shift_left/imm32/subx-name
31700     3/imm32/rm32-is-first-output
31701     0/imm32/no-r32
31702     0/imm32/no-imm32
31703     1/imm32/imm8-is-first-inout
31704     0/imm32/no-disp32
31705     0/imm32/no-xm32
31706     0/imm32/no-x32
31707     0x11/imm32/alloc-id:fake
31708     _Primitive-shift-reg-right-by-lit/imm32/next
31709 _Primitive-shift-reg-right-by-lit:  # (payload primitive)
31710     0x11/imm32/alloc-id:fake:payload
31711     # var1/reg <- shift-right lit => c1/shift 5/subop/right var1/rm32 lit/imm32
31712     0x11/imm32/alloc-id:fake
31713     _string-shift-right/imm32/name
31714     0x11/imm32/alloc-id:fake
31715     Single-lit-var/imm32/inouts
31716     0x11/imm32/alloc-id:fake
31717     Single-int-var-in-some-register/imm32/outputs
31718     0x11/imm32/alloc-id:fake
31719     _string_c1_subop_shift_right_padding_zeroes/imm32/subx-name
31720     3/imm32/rm32-is-first-output
31721     0/imm32/no-r32
31722     0/imm32/no-imm32
31723     1/imm32/imm8-is-first-inout
31724     0/imm32/no-disp32
31725     0/imm32/no-xm32
31726     0/imm32/no-x32
31727     0x11/imm32/alloc-id:fake
31728     _Primitive-shift-reg-right-signed-by-lit/imm32/next
31729 _Primitive-shift-reg-right-signed-by-lit:  # (payload primitive)
31730     0x11/imm32/alloc-id:fake:payload
31731     # var1/reg <- shift-right-signed lit => c1/shift 7/subop/right-preserving-sign var1/rm32 lit/imm32
31732     0x11/imm32/alloc-id:fake
31733     _string-shift-right-signed/imm32/name
31734     0x11/imm32/alloc-id:fake
31735     Single-lit-var/imm32/inouts
31736     0x11/imm32/alloc-id:fake
31737     Single-int-var-in-some-register/imm32/outputs
31738     0x11/imm32/alloc-id:fake
31739     _string_c1_subop_shift_right_preserving_sign/imm32/subx-name
31740     3/imm32/rm32-is-first-output
31741     0/imm32/no-r32
31742     0/imm32/no-imm32
31743     1/imm32/imm8-is-first-inout
31744     0/imm32/no-disp32
31745     0/imm32/no-xm32
31746     0/imm32/no-x32
31747     0x11/imm32/alloc-id:fake
31748     _Primitive-shift-mem-left-by-lit/imm32/next
31749 _Primitive-shift-mem-left-by-lit:  # (payload primitive)
31750     0x11/imm32/alloc-id:fake:payload
31751     # shift-left var1, lit => c1/shift 4/subop/left var1/rm32 lit/imm32
31752     0x11/imm32/alloc-id:fake
31753     _string-shift-left/imm32/name
31754     0x11/imm32/alloc-id:fake
31755     Int-var-and-literal/imm32/inouts
31756     0/imm32/no-outputs
31757     0/imm32/no-outputs
31758     0x11/imm32/alloc-id:fake
31759     _string_c1_subop_shift_left/imm32/subx-name
31760     1/imm32/rm32-is-first-inout
31761     0/imm32/no-r32
31762     0/imm32/no-imm32
31763     2/imm32/imm8-is-second-inout
31764     0/imm32/no-disp32
31765     0/imm32/no-xm32
31766     0/imm32/no-x32
31767     0x11/imm32/alloc-id:fake
31768     _Primitive-shift-mem-right-by-lit/imm32/next
31769 _Primitive-shift-mem-right-by-lit:  # (payload primitive)
31770     0x11/imm32/alloc-id:fake:payload
31771     # shift-right var1, lit => c1/shift 5/subop/right var1/rm32 lit/imm32
31772     0x11/imm32/alloc-id:fake
31773     _string-shift-right/imm32/name
31774     0x11/imm32/alloc-id:fake
31775     Int-var-and-literal/imm32/inouts
31776     0/imm32/no-outputs
31777     0/imm32/no-outputs
31778     0x11/imm32/alloc-id:fake
31779     _string_c1_subop_shift_right_padding_zeroes/imm32/subx-name
31780     1/imm32/rm32-is-first-inout
31781     0/imm32/no-r32
31782     0/imm32/no-imm32
31783     2/imm32/imm8-is-second-inout
31784     0/imm32/no-disp32
31785     0/imm32/no-xm32
31786     0/imm32/no-x32
31787     0x11/imm32/alloc-id:fake
31788     _Primitive-shift-mem-right-signed-by-lit/imm32/next
31789 _Primitive-shift-mem-right-signed-by-lit:  # (payload primitive)
31790     0x11/imm32/alloc-id:fake:payload
31791     # shift-right-signed var1, lit => c1/shift 7/subop/right-preserving-sign var1/rm32 lit/imm32
31792     0x11/imm32/alloc-id:fake
31793     _string-shift-right-signed/imm32/name
31794     0x11/imm32/alloc-id:fake
31795     Int-var-and-literal/imm32/inouts
31796     0/imm32/no-outputs
31797     0/imm32/no-outputs
31798     0x11/imm32/alloc-id:fake
31799     _string_c1_subop_shift_right_preserving_sign/imm32/subx-name
31800     1/imm32/rm32-is-first-inout
31801     0/imm32/no-r32
31802     0/imm32/no-imm32
31803     2/imm32/imm8-is-second-inout
31804     0/imm32/no-disp32
31805     0/imm32/no-xm32
31806     0/imm32/no-x32
31807     0x11/imm32/alloc-id:fake
31808     _Primitive-copy-to-eax/imm32/next
31809 # - copy
31810 _Primitive-copy-to-eax:  # (payload primitive)
31811     0x11/imm32/alloc-id:fake:payload
31812     # var/eax <- copy lit => b8/copy-to-eax lit/imm32
31813     0x11/imm32/alloc-id:fake
31814     _string-copy/imm32/name
31815     0x11/imm32/alloc-id:fake
31816     Single-lit-var/imm32/inouts
31817     0x11/imm32/alloc-id:fake
31818     Single-int-var-in-eax/imm32/outputs
31819     0x11/imm32/alloc-id:fake
31820     _string_b8_copy_to_eax/imm32/subx-name
31821     0/imm32/no-rm32
31822     0/imm32/no-r32
31823     1/imm32/imm32-is-first-inout
31824     0/imm32/no-imm8
31825     0/imm32/no-disp32
31826     0/imm32/no-xm32
31827     0/imm32/no-x32
31828     0x11/imm32/alloc-id:fake
31829     _Primitive-copy-to-ecx/imm32/next
31830 _Primitive-copy-to-ecx:  # (payload primitive)
31831     0x11/imm32/alloc-id:fake:payload
31832     # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32
31833     0x11/imm32/alloc-id:fake
31834     _string-copy/imm32/name
31835     0x11/imm32/alloc-id:fake
31836     Single-lit-var/imm32/inouts
31837     0x11/imm32/alloc-id:fake
31838     Single-int-var-in-ecx/imm32/outputs
31839     0x11/imm32/alloc-id:fake
31840     _string_b9_copy_to_ecx/imm32/subx-name
31841     0/imm32/no-rm32
31842     0/imm32/no-r32
31843     1/imm32/imm32-is-first-inout
31844     0/imm32/no-imm8
31845     0/imm32/no-disp32
31846     0/imm32/no-xm32
31847     0/imm32/no-x32
31848     0x11/imm32/alloc-id:fake
31849     _Primitive-copy-to-edx/imm32/next
31850 _Primitive-copy-to-edx:  # (payload primitive)
31851     0x11/imm32/alloc-id:fake:payload
31852     # var/edx <- copy lit => ba/copy-to-edx lit/imm32
31853     0x11/imm32/alloc-id:fake
31854     _string-copy/imm32/name
31855     0x11/imm32/alloc-id:fake
31856     Single-lit-var/imm32/inouts
31857     0x11/imm32/alloc-id:fake
31858     Single-int-var-in-edx/imm32/outputs
31859     0x11/imm32/alloc-id:fake
31860     _string_ba_copy_to_edx/imm32/subx-name
31861     0/imm32/no-rm32
31862     0/imm32/no-r32
31863     1/imm32/imm32-is-first-inout
31864     0/imm32/no-imm8
31865     0/imm32/no-disp32
31866     0/imm32/no-xm32
31867     0/imm32/no-x32
31868     0x11/imm32/alloc-id:fake
31869     _Primitive-copy-to-ebx/imm32/next
31870 _Primitive-copy-to-ebx:  # (payload primitive)
31871     0x11/imm32/alloc-id:fake:payload
31872     # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32
31873     0x11/imm32/alloc-id:fake
31874     _string-copy/imm32/name
31875     0x11/imm32/alloc-id:fake
31876     Single-lit-var/imm32/inouts
31877     0x11/imm32/alloc-id:fake
31878     Single-int-var-in-ebx/imm32/outputs
31879     0x11/imm32/alloc-id:fake
31880     _string_bb_copy_to_ebx/imm32/subx-name
31881     0/imm32/no-rm32
31882     0/imm32/no-r32
31883     1/imm32/imm32-is-first-inout
31884     0/imm32/no-imm8
31885     0/imm32/no-disp32
31886     0/imm32/no-xm32
31887     0/imm32/no-x32
31888     0x11/imm32/alloc-id:fake
31889     _Primitive-copy-to-esi/imm32/next
31890 _Primitive-copy-to-esi:  # (payload primitive)
31891     0x11/imm32/alloc-id:fake:payload
31892     # var/esi <- copy lit => be/copy-to-esi lit/imm32
31893     0x11/imm32/alloc-id:fake
31894     _string-copy/imm32/name
31895     0x11/imm32/alloc-id:fake
31896     Single-lit-var/imm32/inouts
31897     0x11/imm32/alloc-id:fake
31898     Single-int-var-in-esi/imm32/outputs
31899     0x11/imm32/alloc-id:fake
31900     _string_be_copy_to_esi/imm32/subx-name
31901     0/imm32/no-rm32
31902     0/imm32/no-r32
31903     1/imm32/imm32-is-first-inout
31904     0/imm32/no-imm8
31905     0/imm32/no-disp32
31906     0/imm32/no-xm32
31907     0/imm32/no-x32
31908     0x11/imm32/alloc-id:fake
31909     _Primitive-copy-to-edi/imm32/next
31910 _Primitive-copy-to-edi:  # (payload primitive)
31911     0x11/imm32/alloc-id:fake:payload
31912     # var/edi <- copy lit => bf/copy-to-edi lit/imm32
31913     0x11/imm32/alloc-id:fake
31914     _string-copy/imm32/name
31915     0x11/imm32/alloc-id:fake
31916     Single-lit-var/imm32/inouts
31917     0x11/imm32/alloc-id:fake
31918     Single-int-var-in-edi/imm32/outputs
31919     0x11/imm32/alloc-id:fake
31920     _string_bf_copy_to_edi/imm32/subx-name
31921     0/imm32/no-rm32
31922     0/imm32/no-r32
31923     1/imm32/imm32-is-first-inout
31924     0/imm32/no-imm8
31925     0/imm32/no-disp32
31926     0/imm32/no-xm32
31927     0/imm32/no-x32
31928     0x11/imm32/alloc-id:fake
31929     _Primitive-copy-reg-to-reg/imm32/next
31930 _Primitive-copy-reg-to-reg:  # (payload primitive)
31931     0x11/imm32/alloc-id:fake:payload
31932     # var1/reg <- copy var2/reg => 89/<- var1/rm32 var2/r32
31933     0x11/imm32/alloc-id:fake
31934     _string-copy/imm32/name
31935     0x11/imm32/alloc-id:fake
31936     Single-int-var-in-some-register/imm32/inouts
31937     0x11/imm32/alloc-id:fake
31938     Single-int-var-in-some-register/imm32/outputs
31939     0x11/imm32/alloc-id:fake
31940     _string_89_<-/imm32/subx-name
31941     3/imm32/rm32-is-first-output
31942     1/imm32/r32-is-first-inout
31943     0/imm32/no-imm32
31944     0/imm32/no-imm8
31945     0/imm32/no-disp32
31946     0/imm32/no-xm32
31947     0/imm32/no-x32
31948     0x11/imm32/alloc-id:fake
31949     _Primitive-copy-reg-to-mem/imm32/next
31950 _Primitive-copy-reg-to-mem:  # (payload primitive)
31951     0x11/imm32/alloc-id:fake:payload
31952     # copy-to var1 var2/reg => 89/<- var1 var2/r32
31953     0x11/imm32/alloc-id:fake
31954     _string-copy-to/imm32/name
31955     0x11/imm32/alloc-id:fake
31956     Two-args-int-stack-int-reg/imm32/inouts
31957     0/imm32/no-outputs
31958     0/imm32/no-outputs
31959     0x11/imm32/alloc-id:fake
31960     _string_89_<-/imm32/subx-name
31961     1/imm32/rm32-is-first-inout
31962     2/imm32/r32-is-second-inout
31963     0/imm32/no-imm32
31964     0/imm32/no-imm8
31965     0/imm32/no-disp32
31966     0/imm32/no-xm32
31967     0/imm32/no-x32
31968     0x11/imm32/alloc-id:fake
31969     _Primitive-copy-mem-to-reg/imm32/next
31970 _Primitive-copy-mem-to-reg:  # (payload primitive)
31971     0x11/imm32/alloc-id:fake:payload
31972     # var1/reg <- copy var2 => 8b/-> var2/rm32 var1/r32
31973     0x11/imm32/alloc-id:fake
31974     _string-copy/imm32/name
31975     0x11/imm32/alloc-id:fake
31976     Single-int-var-in-mem/imm32/inouts
31977     0x11/imm32/alloc-id:fake
31978     Single-int-var-in-some-register/imm32/outputs
31979     0x11/imm32/alloc-id:fake
31980     _string_8b_->/imm32/subx-name
31981     1/imm32/rm32-is-first-inout
31982     3/imm32/r32-is-first-output
31983     0/imm32/no-imm32
31984     0/imm32/no-imm8
31985     0/imm32/no-disp32
31986     0/imm32/no-xm32
31987     0/imm32/no-x32
31988     0x11/imm32/alloc-id:fake
31989     _Primitive-copy-lit-to-reg/imm32/next
31990 _Primitive-copy-lit-to-reg:  # (payload primitive)
31991     0x11/imm32/alloc-id:fake:payload
31992     # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32
31993     0x11/imm32/alloc-id:fake
31994     _string-copy/imm32/name
31995     0x11/imm32/alloc-id:fake
31996     Single-lit-var/imm32/inouts
31997     0x11/imm32/alloc-id:fake
31998     Single-int-var-in-some-register/imm32/outputs
31999     0x11/imm32/alloc-id:fake
32000     _string_c7_subop_copy/imm32/subx-name
32001     3/imm32/rm32-is-first-output
32002     0/imm32/no-r32
32003     1/imm32/imm32-is-first-inout
32004     0/imm32/no-imm8
32005     0/imm32/no-disp32
32006     0/imm32/no-xm32
32007     0/imm32/no-x32
32008     0x11/imm32/alloc-id:fake
32009     _Primitive-copy-lit-to-mem/imm32/next
32010 _Primitive-copy-lit-to-mem:  # (payload primitive)
32011     0x11/imm32/alloc-id:fake:payload
32012     # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32
32013     0x11/imm32/alloc-id:fake
32014     _string-copy-to/imm32/name
32015     0x11/imm32/alloc-id:fake
32016     Int-var-and-literal/imm32/inouts
32017     0/imm32/no-outputs
32018     0/imm32/no-outputs
32019     0x11/imm32/alloc-id:fake
32020     _string_c7_subop_copy/imm32/subx-name
32021     1/imm32/rm32-is-first-inout
32022     0/imm32/no-r32
32023     2/imm32/imm32-is-second-inout
32024     0/imm32/no-imm8
32025     0/imm32/no-disp32
32026     0/imm32/no-xm32
32027     0/imm32/no-x32
32028     0x11/imm32/alloc-id:fake
32029     _Primitive-copy-byte-from-reg/imm32/next
32030 # - copy byte
32031 _Primitive-copy-byte-from-reg:
32032     0x11/imm32/alloc-id:fake:payload
32033     # var/reg <- copy-byte var2/reg2 => 8a/byte-> %var2 var/r32
32034     0x11/imm32/alloc-id:fake
32035     _string-copy-byte/imm32/name
32036     0x11/imm32/alloc-id:fake
32037     Single-byte-var-in-some-register/imm32/inouts
32038     0x11/imm32/alloc-id:fake
32039     Single-byte-var-in-some-register/imm32/outputs
32040     0x11/imm32/alloc-id:fake
32041     _string_8a_copy_byte/imm32/subx-name
32042     1/imm32/rm32-is-first-inout
32043     3/imm32/r32-is-first-output
32044     0/imm32/no-imm32
32045     0/imm32/no-imm8
32046     0/imm32/no-disp32
32047     0/imm32/no-xm32
32048     0/imm32/no-x32
32049     0x11/imm32/alloc-id:fake
32050     _Primitive-copy-byte-from-mem/imm32/next
32051 _Primitive-copy-byte-from-mem:
32052     0x11/imm32/alloc-id:fake:payload
32053     # var/reg <- copy-byte *var2/reg2 => 8a/byte-> *var2 var/r32
32054     0x11/imm32/alloc-id:fake
32055     _string-copy-byte/imm32/name
32056     0x11/imm32/alloc-id:fake
32057     Single-byte-var-in-mem/imm32/inouts
32058     0x11/imm32/alloc-id:fake
32059     Single-byte-var-in-some-register/imm32/outputs
32060     0x11/imm32/alloc-id:fake
32061     _string_8a_copy_byte/imm32/subx-name
32062     1/imm32/rm32-is-first-inout
32063     3/imm32/r32-is-first-output
32064     0/imm32/no-imm32
32065     0/imm32/no-imm8
32066     0/imm32/no-disp32
32067     0/imm32/no-xm32
32068     0/imm32/no-x32
32069     0x11/imm32/alloc-id:fake
32070     _Primitive-copy-byte-to-mem/imm32/next
32071 _Primitive-copy-byte-to-mem:
32072     0x11/imm32/alloc-id:fake:payload
32073     # copy-byte-to *var1/reg1, var2/reg2 => 88/byte<- *reg1 reg2/r32
32074     0x11/imm32/alloc-id:fake
32075     _string-copy-byte-to/imm32/name
32076     0x11/imm32/alloc-id:fake
32077     Two-args-byte-stack-byte-reg/imm32/inouts
32078     0/imm32/no-outputs
32079     0/imm32/no-outputs
32080     0x11/imm32/alloc-id:fake
32081     _string_88_copy_byte/imm32/subx-name
32082     1/imm32/rm32-is-first-inout
32083     2/imm32/r32-is-second-inout
32084     0/imm32/no-imm32
32085     0/imm32/no-imm8
32086     0/imm32/no-disp32
32087     0/imm32/no-xm32
32088     0/imm32/no-x32
32089     0x11/imm32/alloc-id:fake
32090     _Primitive-address/imm32/next
32091 # - address
32092 _Primitive-address:  # (payload primitive)
32093     0x11/imm32/alloc-id:fake:payload
32094     # var1/reg <- address var2 => 8d/copy-address var2/rm32 var1/r32
32095     0x11/imm32/alloc-id:fake
32096     _string-address/imm32/name
32097     0x11/imm32/alloc-id:fake
32098     Single-int-var-in-mem/imm32/inouts
32099     0x11/imm32/alloc-id:fake
32100     Single-addr-var-in-some-register/imm32/outputs
32101     0x11/imm32/alloc-id:fake
32102     _string_8d_copy_address/imm32/subx-name
32103     1/imm32/rm32-is-first-inout
32104     3/imm32/r32-is-first-output
32105     0/imm32/no-imm32
32106     0/imm32/no-imm8
32107     0/imm32/no-disp32
32108     0/imm32/no-xm32
32109     0/imm32/no-x32
32110     0x11/imm32/alloc-id:fake
32111     _Primitive-compare-reg-with-reg/imm32/next
32112 # - compare
32113 _Primitive-compare-reg-with-reg:  # (payload primitive)
32114     0x11/imm32/alloc-id:fake:payload
32115     # compare var1/reg1 var2/reg2 => 39/compare var1/rm32 var2/r32
32116     0x11/imm32/alloc-id:fake
32117     _string-compare/imm32/name
32118     0x11/imm32/alloc-id:fake
32119     Two-int-args-in-regs/imm32/inouts
32120     0/imm32/no-outputs
32121     0/imm32/no-outputs
32122     0x11/imm32/alloc-id:fake
32123     _string_39_compare->/imm32/subx-name
32124     1/imm32/rm32-is-first-inout
32125     2/imm32/r32-is-second-inout
32126     0/imm32/no-imm32
32127     0/imm32/no-imm8
32128     0/imm32/no-disp32
32129     0/imm32/no-xm32
32130     0/imm32/no-x32
32131     0x11/imm32/alloc-id:fake
32132     _Primitive-compare-mem-with-reg/imm32/next
32133 _Primitive-compare-mem-with-reg:  # (payload primitive)
32134     0x11/imm32/alloc-id:fake:payload
32135     # compare var1 var2/reg => 39/compare var1/rm32 var2/r32
32136     0x11/imm32/alloc-id:fake
32137     _string-compare/imm32/name
32138     0x11/imm32/alloc-id:fake
32139     Two-args-int-stack-int-reg/imm32/inouts
32140     0/imm32/no-outputs
32141     0/imm32/no-outputs
32142     0x11/imm32/alloc-id:fake
32143     _string_39_compare->/imm32/subx-name
32144     1/imm32/rm32-is-first-inout
32145     2/imm32/r32-is-second-inout
32146     0/imm32/no-imm32
32147     0/imm32/no-imm8
32148     0/imm32/no-disp32
32149     0/imm32/no-xm32
32150     0/imm32/no-x32
32151     0x11/imm32/alloc-id:fake
32152     _Primitive-compare-reg-with-mem/imm32/next
32153 _Primitive-compare-reg-with-mem:  # (payload primitive)
32154     0x11/imm32/alloc-id:fake:payload
32155     # compare var1/reg var2 => 3b/compare<- var2/rm32 var1/r32
32156     0x11/imm32/alloc-id:fake
32157     _string-compare/imm32/name
32158     0x11/imm32/alloc-id:fake
32159     Two-args-int-reg-int-stack/imm32/inouts
32160     0/imm32/no-outputs
32161     0/imm32/no-outputs
32162     0x11/imm32/alloc-id:fake
32163     _string_3b_compare<-/imm32/subx-name
32164     2/imm32/rm32-is-second-inout
32165     1/imm32/r32-is-first-inout
32166     0/imm32/no-imm32
32167     0/imm32/no-imm8
32168     0/imm32/no-disp32
32169     0/imm32/no-xm32
32170     0/imm32/no-x32
32171     0x11/imm32/alloc-id:fake
32172     _Primitive-compare-eax-with-literal/imm32/next
32173 _Primitive-compare-eax-with-literal:  # (payload primitive)
32174     0x11/imm32/alloc-id:fake:payload
32175     # compare var1/eax n => 3d/compare-eax-with n/imm32
32176     0x11/imm32/alloc-id:fake
32177     _string-compare/imm32/name
32178     0x11/imm32/alloc-id:fake
32179     Two-args-int-eax-int-literal/imm32/inouts
32180     0/imm32/no-outputs
32181     0/imm32/no-outputs
32182     0x11/imm32/alloc-id:fake
32183     _string_3d_compare_eax_with/imm32/subx-name
32184     0/imm32/no-rm32
32185     0/imm32/no-r32
32186     2/imm32/imm32-is-second-inout
32187     0/imm32/no-imm8
32188     0/imm32/no-disp32
32189     0/imm32/no-xm32
32190     0/imm32/no-x32
32191     0x11/imm32/alloc-id:fake
32192     _Primitive-compare-reg-with-literal/imm32/next
32193 _Primitive-compare-reg-with-literal:  # (payload primitive)
32194     0x11/imm32/alloc-id:fake:payload
32195     # compare var1/reg n => 81 7/subop/compare %reg n/imm32
32196     0x11/imm32/alloc-id:fake
32197     _string-compare/imm32/name
32198     0x11/imm32/alloc-id:fake
32199     Int-var-in-register-and-literal/imm32/inouts
32200     0/imm32/no-outputs
32201     0/imm32/no-outputs
32202     0x11/imm32/alloc-id:fake
32203     _string_81_subop_compare/imm32/subx-name
32204     1/imm32/rm32-is-first-inout
32205     0/imm32/no-r32
32206     2/imm32/imm32-is-second-inout
32207     0/imm32/no-imm8
32208     0/imm32/no-disp32
32209     0/imm32/no-xm32
32210     0/imm32/no-x32
32211     0x11/imm32/alloc-id:fake
32212     _Primitive-compare-mem-with-literal/imm32/next
32213 _Primitive-compare-mem-with-literal:  # (payload primitive)
32214     0x11/imm32/alloc-id:fake:payload
32215     # compare var1 n => 81 7/subop/compare *(ebp+___) n/imm32
32216     0x11/imm32/alloc-id:fake
32217     _string-compare/imm32/name
32218     0x11/imm32/alloc-id:fake
32219     Int-var-and-literal/imm32/inouts
32220     0/imm32/no-outputs
32221     0/imm32/no-outputs
32222     0x11/imm32/alloc-id:fake
32223     _string_81_subop_compare/imm32/subx-name
32224     1/imm32/rm32-is-first-inout
32225     0/imm32/no-r32
32226     2/imm32/imm32-is-second-inout
32227     0/imm32/no-imm8
32228     0/imm32/no-disp32
32229     0/imm32/no-xm32
32230     0/imm32/no-x32
32231     0x11/imm32/alloc-id:fake
32232     _Primitive-negate-reg/imm32/next
32233 # - negate
32234 _Primitive-negate-reg:  # (payload primitive)
32235     0x11/imm32/alloc-id:fake:payload
32236     # var1/reg <- negate => f7 3/subop/negate var1/rm32
32237     0x11/imm32/alloc-id:fake
32238     _string-negate/imm32/name
32239     0/imm32/no-inouts
32240     0/imm32/no-inouts
32241     0x11/imm32/alloc-id:fake
32242     Single-int-var-in-some-register/imm32/outputs
32243     0x11/imm32/alloc-id:fake
32244     _string_f7_subop_negate/imm32/subx-name
32245     3/imm32/rm32-is-first-output
32246     0/imm32/no-r32
32247     0/imm32/no-imm32
32248     0/imm32/no-imm8
32249     0/imm32/no-disp32
32250     0/imm32/no-xm32
32251     0/imm32/no-x32
32252     0x11/imm32/alloc-id:fake
32253     _Primitive-negate-mem/imm32/next
32254 _Primitive-negate-mem:  # (payload primitive)
32255     0x11/imm32/alloc-id:fake:payload
32256     # negate var1 => f7 3/subop/negate var1/rm32
32257     0x11/imm32/alloc-id:fake
32258     _string-negate/imm32/name
32259     0x11/imm32/alloc-id:fake
32260     Single-int-var-in-mem/imm32/inouts
32261     0/imm32/no-outputs
32262     0/imm32/no-outputs
32263     0x11/imm32/alloc-id:fake
32264     _string_f7_subop_negate/imm32/subx-name
32265     1/imm32/rm32-is-first-inout
32266     0/imm32/no-r32
32267     0/imm32/no-imm32
32268     0/imm32/no-imm8
32269     0/imm32/no-disp32
32270     0/imm32/no-xm32
32271     0/imm32/no-x32
32272     0x11/imm32/alloc-id:fake
32273     _Primitive-multiply-reg-by-reg/imm32/next
32274 # - multiply
32275 _Primitive-multiply-reg-by-reg:  # (payload primitive)
32276     0x11/imm32/alloc-id:fake:payload
32277     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
32278     0x11/imm32/alloc-id:fake
32279     _string-multiply/imm32/name
32280     0x11/imm32/alloc-id:fake
32281     Single-int-var-in-some-register/imm32/inouts
32282     0x11/imm32/alloc-id:fake
32283     Single-int-var-in-some-register/imm32/outputs
32284     0x11/imm32/alloc-id:fake
32285     _string_0f_af_multiply/imm32/subx-name
32286     1/imm32/rm32-is-first-inout
32287     3/imm32/r32-is-first-output
32288     0/imm32/no-imm32
32289     0/imm32/no-imm8
32290     0/imm32/no-disp32
32291     0/imm32/no-xm32
32292     0/imm32/no-x32
32293     0x11/imm32/alloc-id:fake
32294     _Primitive-multiply-reg-by-mem/imm32/next
32295 _Primitive-multiply-reg-by-mem:  # (payload primitive)
32296     0x11/imm32/alloc-id:fake:payload
32297     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
32298     0x11/imm32/alloc-id:fake
32299     _string-multiply/imm32/name
32300     0x11/imm32/alloc-id:fake
32301     Single-int-var-in-mem/imm32/inouts
32302     0x11/imm32/alloc-id:fake
32303     Single-int-var-in-some-register/imm32/outputs
32304     0x11/imm32/alloc-id:fake
32305     _string_0f_af_multiply/imm32/subx-name
32306     1/imm32/rm32-is-first-inout
32307     3/imm32/r32-is-first-output
32308     0/imm32/no-imm32
32309     0/imm32/no-imm8
32310     0/imm32/no-disp32
32311     0/imm32/no-xm32
32312     0/imm32/no-x32
32313     0x11/imm32/alloc-id:fake
32314     _Primitive-convert-mem-to-xreg/imm32/next
32315 # - convert int to floating point
32316 _Primitive-convert-mem-to-xreg:  # (payload primitive)
32317     0x11/imm32/alloc-id:fake:payload
32318     # var1/xreg <- convert var2 => f3 0f 2a/convert-to-float var2/rm32 var1/x32
32319     0x11/imm32/alloc-id:fake
32320     _string-convert/imm32/name
32321     0x11/imm32/alloc-id:fake
32322     Single-int-var-in-mem/imm32/inouts
32323     0x11/imm32/alloc-id:fake
32324     Single-float-var-in-some-register/imm32/outputs
32325     0x11/imm32/alloc-id:fake
32326     _string_f3_0f_2a_convert_to_float/imm32/subx-name
32327     1/imm32/rm32-is-first-inout
32328     0/imm32/no-r32
32329     0/imm32/no-imm32
32330     0/imm32/no-imm8
32331     0/imm32/no-disp32
32332     0/imm32/no-xm32
32333     3/imm32/x32-is-first-output
32334     0x11/imm32/alloc-id:fake
32335     _Primitive-convert-reg-to-xreg/imm32/next
32336 _Primitive-convert-reg-to-xreg:  # (payload primitive)
32337     0x11/imm32/alloc-id:fake:payload
32338     # var1/xreg <- convert var2/reg => f3 0f 2a/convert-to-float var2/rm32 var1/x32
32339     0x11/imm32/alloc-id:fake
32340     _string-convert/imm32/name
32341     0x11/imm32/alloc-id:fake
32342     Single-int-var-in-some-register/imm32/inouts
32343     0x11/imm32/alloc-id:fake
32344     Single-float-var-in-some-register/imm32/outputs
32345     0x11/imm32/alloc-id:fake
32346     _string_f3_0f_2a_convert_to_float/imm32/subx-name
32347     1/imm32/rm32-is-first-inout
32348     0/imm32/no-r32
32349     0/imm32/no-imm32
32350     0/imm32/no-imm8
32351     0/imm32/no-disp32
32352     0/imm32/no-xm32
32353     3/imm32/x32-is-first-output
32354     0x11/imm32/alloc-id:fake
32355     _Primitive-convert-xmem-to-reg/imm32/next
32356 # - convert floating point to int
32357 _Primitive-convert-xmem-to-reg:  # (payload primitive)
32358     0x11/imm32/alloc-id:fake:payload
32359     # var1/reg <- convert var2 => f3 0f 2d/convert-to-int var2/xm32 var1/r32
32360     0x11/imm32/alloc-id:fake
32361     _string-convert/imm32/name
32362     0x11/imm32/alloc-id:fake
32363     Single-float-var-in-mem/imm32/inouts
32364     0x11/imm32/alloc-id:fake
32365     Single-int-var-in-some-register/imm32/outputs
32366     0x11/imm32/alloc-id:fake
32367     _string_f3_0f_2d_convert_to_int/imm32/subx-name
32368     0/imm32/no-rm32
32369     3/imm32/r32-is-first-output
32370     0/imm32/no-imm32
32371     0/imm32/no-imm8
32372     0/imm32/no-disp32
32373     1/imm32/xm32-is-first-inout
32374     0/imm32/no-x32
32375     0x11/imm32/alloc-id:fake
32376     _Primitive-convert-xreg-to-reg/imm32/next
32377 _Primitive-convert-xreg-to-reg:  # (payload primitive)
32378     0x11/imm32/alloc-id:fake:payload
32379     # var1/reg <- convert var2/xreg => f3 0f 2d/convert-to-int var2/xm32 var1/r32
32380     0x11/imm32/alloc-id:fake
32381     _string-convert/imm32/name
32382     0x11/imm32/alloc-id:fake
32383     Single-float-var-in-some-register/imm32/inouts
32384     0x11/imm32/alloc-id:fake
32385     Single-int-var-in-some-register/imm32/outputs
32386     0x11/imm32/alloc-id:fake
32387     _string_f3_0f_2d_convert_to_int/imm32/subx-name
32388     0/imm32/no-rm32
32389     3/imm32/r32-is-first-output
32390     0/imm32/no-imm32
32391     0/imm32/no-imm8
32392     0/imm32/no-disp32
32393     1/imm32/xm32-is-first-inout
32394     0/imm32/no-x32
32395     0x11/imm32/alloc-id:fake
32396     _Primitive-truncate-xmem-to-reg/imm32/next
32397 _Primitive-truncate-xmem-to-reg:  # (payload primitive)
32398     0x11/imm32/alloc-id:fake:payload
32399     # var1/reg <- truncate var2 => f3 0f 2c/truncate-to-int var2/xm32 var1/r32
32400     0x11/imm32/alloc-id:fake
32401     _string-truncate/imm32/name
32402     0x11/imm32/alloc-id:fake
32403     Single-float-var-in-mem/imm32/inouts
32404     0x11/imm32/alloc-id:fake
32405     Single-int-var-in-some-register/imm32/outputs
32406     0x11/imm32/alloc-id:fake
32407     _string_f3_0f_2c_truncate_to_int/imm32/subx-name
32408     0/imm32/no-rm32
32409     3/imm32/r32-is-first-output
32410     0/imm32/no-imm32
32411     0/imm32/no-imm8
32412     0/imm32/no-disp32
32413     1/imm32/xm32-is-first-inout
32414     0/imm32/no-x32
32415     0x11/imm32/alloc-id:fake
32416     _Primitive-truncate-xreg-to-reg/imm32/next
32417 _Primitive-truncate-xreg-to-reg:  # (payload primitive)
32418     0x11/imm32/alloc-id:fake:payload
32419     # var1/reg <- truncate var2/xreg => f3 0f 2c/truncate-to-int var2/xm32 var1/r32
32420     0x11/imm32/alloc-id:fake
32421     _string-truncate/imm32/name
32422     0x11/imm32/alloc-id:fake
32423     Single-float-var-in-some-register/imm32/inouts
32424     0x11/imm32/alloc-id:fake
32425     Single-int-var-in-some-register/imm32/outputs
32426     0x11/imm32/alloc-id:fake
32427     _string_f3_0f_2c_truncate_to_int/imm32/subx-name
32428     0/imm32/no-rm32
32429     3/imm32/r32-is-first-output
32430     0/imm32/no-imm32
32431     0/imm32/no-imm8
32432     0/imm32/no-disp32
32433     1/imm32/xm32-is-first-inout
32434     0/imm32/no-x32
32435     0x11/imm32/alloc-id:fake
32436     _Primitive-reinterpret-xmem-as-reg/imm32/next
32437 # - reinterpret bytes (just for debugging)
32438 _Primitive-reinterpret-xmem-as-reg:  # (payload primitive)
32439     0x11/imm32/alloc-id:fake:payload
32440     # var1/reg <- reinterpret var2 => 8b/-> var2/xm32 var1/r32
32441     0x11/imm32/alloc-id:fake
32442     _string-reinterpret/imm32/name
32443     0x11/imm32/alloc-id:fake
32444     Single-float-var-in-mem/imm32/inouts
32445     0x11/imm32/alloc-id:fake
32446     Single-int-var-in-some-register/imm32/outputs
32447     0x11/imm32/alloc-id:fake
32448     _string_8b_->/imm32/subx-name
32449     0/imm32/no-rm32
32450     3/imm32/r32-is-first-output
32451     0/imm32/no-imm32
32452     0/imm32/no-imm8
32453     0/imm32/no-disp32
32454     1/imm32/xm32-is-first-inout
32455     0/imm32/no-x32
32456     0x11/imm32/alloc-id:fake
32457     _Primitive-reinterpret-mem-as-xreg/imm32/next
32458 _Primitive-reinterpret-mem-as-xreg:  # (payload primitive)
32459     0x11/imm32/alloc-id:fake:payload
32460     # var1/xreg <- reinterpret var2 => f3 0f 10/-> var2/rm32 var1/x32
32461     0x11/imm32/alloc-id:fake
32462     _string-reinterpret/imm32/name
32463     0x11/imm32/alloc-id:fake
32464     Single-int-var-in-mem/imm32/inouts
32465     0x11/imm32/alloc-id:fake
32466     Single-float-var-in-some-register/imm32/outputs
32467     0x11/imm32/alloc-id:fake
32468     _string_f3_0f_10_copy/imm32/subx-name
32469     1/imm32/rm32-is-first-inout
32470     0/imm32/no-r32
32471     0/imm32/no-imm32
32472     0/imm32/no-imm8
32473     0/imm32/no-disp32
32474     0/imm32/no-xm32
32475     3/imm32/x32-is-first-output
32476     0x11/imm32/alloc-id:fake
32477     _Primitive-copy-xreg-to-xreg/imm32/next
32478 # - floating-point copy
32479 _Primitive-copy-xreg-to-xreg:  # (payload primitive)
32480     0x11/imm32/alloc-id:fake:payload
32481     # var1/xreg <- copy var2/xreg => f3 0f 11/<- var1/xm32 var2/x32
32482     0x11/imm32/alloc-id:fake
32483     _string-copy/imm32/name
32484     0x11/imm32/alloc-id:fake
32485     Single-float-var-in-some-register/imm32/inouts
32486     0x11/imm32/alloc-id:fake
32487     Single-float-var-in-some-register/imm32/outputs
32488     0x11/imm32/alloc-id:fake
32489     _string_f3_0f_11_copy/imm32/subx-name
32490     0/imm32/no-rm32
32491     0/imm32/no-r32
32492     0/imm32/no-imm32
32493     0/imm32/no-imm8
32494     0/imm32/no-disp32
32495     3/imm32/xm32-is-first-output
32496     1/imm32/x32-is-first-inout
32497     0x11/imm32/alloc-id:fake
32498     _Primitive-copy-xreg-to-mem/imm32/next
32499 _Primitive-copy-xreg-to-mem:  # (payload primitive)
32500     0x11/imm32/alloc-id:fake:payload
32501     # copy-to var1 var2/xreg => f3 0f 11/<- var1 var2/x32
32502     0x11/imm32/alloc-id:fake
32503     _string-copy-to/imm32/name
32504     0x11/imm32/alloc-id:fake
32505     Two-args-float-stack-float-reg/imm32/inouts
32506     0/imm32/no-outputs
32507     0/imm32/no-outputs
32508     0x11/imm32/alloc-id:fake
32509     _string_f3_0f_11_copy/imm32/subx-name
32510     0/imm32/no-rm32
32511     0/imm32/no-r32
32512     0/imm32/no-imm32
32513     0/imm32/no-imm8
32514     0/imm32/no-disp32
32515     1/imm32/xm32-is-first-inout
32516     2/imm32/x32-is-second-inout
32517     0x11/imm32/alloc-id:fake
32518     _Primitive-copy-mem-to-xreg/imm32/next
32519 _Primitive-copy-mem-to-xreg:  # (payload primitive)
32520     0x11/imm32/alloc-id:fake:payload
32521     # var1/xreg <- copy var2 => f3 0f 10/-> var2/rm32 var1/x32
32522     0x11/imm32/alloc-id:fake
32523     _string-copy/imm32/name
32524     0x11/imm32/alloc-id:fake
32525     Single-float-var-in-mem/imm32/inouts
32526     0x11/imm32/alloc-id:fake
32527     Single-float-var-in-some-register/imm32/outputs
32528     0x11/imm32/alloc-id:fake
32529     _string_f3_0f_10_copy/imm32/subx-name
32530     0/imm32/no-rm32
32531     0/imm32/no-r32
32532     0/imm32/no-imm32
32533     0/imm32/no-imm8
32534     0/imm32/no-disp32
32535     1/imm32/xm32-is-first-inout
32536     3/imm32/x32-is-first-output
32537     0x11/imm32/alloc-id:fake
32538     _Primitive-address-of-xmem/imm32/next
32539 # - floating-point-address
32540 _Primitive-address-of-xmem:  # (payload primitive)
32541     0x11/imm32/alloc-id:fake:payload
32542     # var1/reg <- address var2 => 8d/copy-address var2/rm32 var1/r32
32543     0x11/imm32/alloc-id:fake
32544     _string-address/imm32/name
32545     0x11/imm32/alloc-id:fake
32546     Single-float-var-in-mem/imm32/inouts
32547     0x11/imm32/alloc-id:fake
32548     Single-addr-var-in-some-register/imm32/outputs
32549     0x11/imm32/alloc-id:fake
32550     _string_8d_copy_address/imm32/subx-name
32551     1/imm32/rm32-is-first-inout
32552     3/imm32/r32-is-first-output
32553     0/imm32/no-imm32
32554     0/imm32/no-imm8
32555     0/imm32/no-disp32
32556     0/imm32/no-xm32
32557     0/imm32/no-x32
32558     0x11/imm32/alloc-id:fake
32559     _Primitive-add-xreg-to-xreg/imm32/next
32560 # - floating-point add
32561 _Primitive-add-xreg-to-xreg:  # (payload primitive)
32562     0x11/imm32/alloc-id:fake:payload
32563     # var1/xreg <- add var2/xreg => f3 0f 58/add var1/xm32 var2/x32
32564     0x11/imm32/alloc-id:fake
32565     _string-add/imm32/name
32566     0x11/imm32/alloc-id:fake
32567     Single-float-var-in-some-register/imm32/inouts
32568     0x11/imm32/alloc-id:fake
32569     Single-float-var-in-some-register/imm32/outputs
32570     0x11/imm32/alloc-id:fake
32571     _string_f3_0f_58_add/imm32/subx-name
32572     0/imm32/no-rm32
32573     0/imm32/no-r32
32574     0/imm32/no-imm32
32575     0/imm32/no-imm8
32576     0/imm32/no-disp32
32577     1/imm32/xm32-is-first-inout
32578     3/imm32/x32-is-first-output
32579     0x11/imm32/alloc-id:fake
32580     _Primitive-add-mem-to-xreg/imm32/next
32581 _Primitive-add-mem-to-xreg:  # (payload primitive)
32582     0x11/imm32/alloc-id:fake:payload
32583     # var1/xreg <- add var2 => f3 0f 58/add var2/xm32 var1/x32
32584     0x11/imm32/alloc-id:fake
32585     _string-add/imm32/name
32586     0x11/imm32/alloc-id:fake
32587     Single-float-var-in-mem/imm32/inouts
32588     0x11/imm32/alloc-id:fake
32589     Single-float-var-in-some-register/imm32/outputs
32590     0x11/imm32/alloc-id:fake
32591     _string_f3_0f_58_add/imm32/subx-name
32592     0/imm32/no-rm32
32593     0/imm32/no-r32
32594     0/imm32/no-imm32
32595     0/imm32/no-imm8
32596     0/imm32/no-disp32
32597     1/imm32/xm32-is-first-inout
32598     3/imm32/x32-is-first-output
32599     0x11/imm32/alloc-id:fake
32600     _Primitive-subtract-xreg-from-xreg/imm32/next
32601 # - floating-point subtract
32602 _Primitive-subtract-xreg-from-xreg:  # (payload primitive)
32603     0x11/imm32/alloc-id:fake:payload
32604     # var1/xreg <- subtract var2/xreg => f3 0f 5c/subtract var1/xm32 var2/x32
32605     0x11/imm32/alloc-id:fake
32606     _string-subtract/imm32/name
32607     0x11/imm32/alloc-id:fake
32608     Single-float-var-in-some-register/imm32/inouts
32609     0x11/imm32/alloc-id:fake
32610     Single-float-var-in-some-register/imm32/outputs
32611     0x11/imm32/alloc-id:fake
32612     _string_f3_0f_5c_subtract/imm32/subx-name
32613     0/imm32/no-rm32
32614     0/imm32/no-r32
32615     0/imm32/no-imm32
32616     0/imm32/no-imm8
32617     0/imm32/no-disp32
32618     1/imm32/xm32-is-first-inout
32619     3/imm32/x32-is-first-output
32620     0x11/imm32/alloc-id:fake
32621     _Primitive-subtract-mem-from-xreg/imm32/next
32622 _Primitive-subtract-mem-from-xreg:  # (payload primitive)
32623     0x11/imm32/alloc-id:fake:payload
32624     # var1/xreg <- subtract var2 => f3 0f 5c/subtract var2/xm32 var1/x32
32625     0x11/imm32/alloc-id:fake
32626     _string-subtract/imm32/name
32627     0x11/imm32/alloc-id:fake
32628     Single-float-var-in-mem/imm32/inouts
32629     0x11/imm32/alloc-id:fake
32630     Single-float-var-in-some-register/imm32/outputs
32631     0x11/imm32/alloc-id:fake
32632     _string_f3_0f_5c_subtract/imm32/subx-name
32633     0/imm32/no-rm32
32634     0/imm32/no-r32
32635     0/imm32/no-imm32
32636     0/imm32/no-imm8
32637     0/imm32/no-disp32
32638     1/imm32/xm32-is-first-inout
32639     3/imm32/x32-is-first-output
32640     0x11/imm32/alloc-id:fake
32641     _Primitive-multiply-xreg-by-xreg/imm32/next
32642 # - floating-point multiply
32643 _Primitive-multiply-xreg-by-xreg:  # (payload primitive)
32644     0x11/imm32/alloc-id:fake:payload
32645     # var1/xreg <- multiply var2 => f3 0f 59/multiply var2/xm32 var1/x32
32646     0x11/imm32/alloc-id:fake
32647     _string-multiply/imm32/name
32648     0x11/imm32/alloc-id:fake
32649     Single-float-var-in-some-register/imm32/inouts
32650     0x11/imm32/alloc-id:fake
32651     Single-float-var-in-some-register/imm32/outputs
32652     0x11/imm32/alloc-id:fake
32653     _string_f3_0f_59_multiply/imm32/subx-name
32654     0/imm32/no-rm32
32655     0/imm32/no-r32
32656     0/imm32/no-imm32
32657     0/imm32/no-imm8
32658     0/imm32/no-disp32
32659     1/imm32/xm32-is-first-inout
32660     3/imm32/x32-is-first-output
32661     0x11/imm32/alloc-id:fake
32662     _Primitive-multiply-xreg-by-mem/imm32/next
32663 _Primitive-multiply-xreg-by-mem:  # (payload primitive)
32664     0x11/imm32/alloc-id:fake:payload
32665     # var1/xreg <- multiply var2 => 53 0f 59/multiply var2/xm32 var1/x32
32666     0x11/imm32/alloc-id:fake
32667     _string-multiply/imm32/name
32668     0x11/imm32/alloc-id:fake
32669     Single-float-var-in-mem/imm32/inouts
32670     0x11/imm32/alloc-id:fake
32671     Single-float-var-in-some-register/imm32/outputs
32672     0x11/imm32/alloc-id:fake
32673     _string_f3_0f_59_multiply/imm32/subx-name
32674     0/imm32/no-rm32
32675     0/imm32/no-r32
32676     0/imm32/no-imm32
32677     0/imm32/no-imm8
32678     0/imm32/no-disp32
32679     1/imm32/xm32-is-first-inout
32680     3/imm32/x32-is-first-output
32681     0x11/imm32/alloc-id:fake
32682     _Primitive-divide-xreg-by-xreg/imm32/next
32683 # - floating-point divide
32684 _Primitive-divide-xreg-by-xreg:  # (payload primitive)
32685     0x11/imm32/alloc-id:fake:payload
32686     # var1/xreg <- divide var2 => f3 0f 5e/divide var2/xm32 var1/x32
32687     0x11/imm32/alloc-id:fake
32688     _string-divide/imm32/name
32689     0x11/imm32/alloc-id:fake
32690     Single-float-var-in-some-register/imm32/inouts
32691     0x11/imm32/alloc-id:fake
32692     Single-float-var-in-some-register/imm32/outputs
32693     0x11/imm32/alloc-id:fake
32694     _string_f3_0f_5e_divide/imm32/subx-name
32695     0/imm32/no-rm32
32696     0/imm32/no-r32
32697     0/imm32/no-imm32
32698     0/imm32/no-imm8
32699     0/imm32/no-disp32
32700     1/imm32/xm32-is-first-inout
32701     3/imm32/x32-is-first-output
32702     0x11/imm32/alloc-id:fake
32703     _Primitive-divide-xreg-by-mem/imm32/next
32704 _Primitive-divide-xreg-by-mem:  # (payload primitive)
32705     0x11/imm32/alloc-id:fake:payload
32706     # var1/xreg <- divide var2 => f3 0f 5e/divide var2/xm32 var1/x32
32707     0x11/imm32/alloc-id:fake
32708     _string-divide/imm32/name
32709     0x11/imm32/alloc-id:fake
32710     Single-float-var-in-mem/imm32/inouts
32711     0x11/imm32/alloc-id:fake
32712     Single-float-var-in-some-register/imm32/outputs
32713     0x11/imm32/alloc-id:fake
32714     _string_f3_0f_5e_divide/imm32/subx-name
32715     0/imm32/no-rm32
32716     0/imm32/no-r32
32717     0/imm32/no-imm32
32718     0/imm32/no-imm8
32719     0/imm32/no-disp32
32720     1/imm32/xm32-is-first-inout
32721     3/imm32/x32-is-first-output
32722     0x11/imm32/alloc-id:fake
32723     _Primitive-max-xreg-with-xreg/imm32/next
32724 # - floating-point maximum
32725 _Primitive-max-xreg-with-xreg:  # (payload primitive)
32726     0x11/imm32/alloc-id:fake:payload
32727     # var1/xreg <- max var2 => f3 0f 5f/max var2/xm32 var1/x32
32728     0x11/imm32/alloc-id:fake
32729     _string-max/imm32/name
32730     0x11/imm32/alloc-id:fake
32731     Single-float-var-in-some-register/imm32/inouts
32732     0x11/imm32/alloc-id:fake
32733     Single-float-var-in-some-register/imm32/outputs
32734     0x11/imm32/alloc-id:fake
32735     _string_f3_0f_5f_max/imm32/subx-name
32736     0/imm32/no-rm32
32737     0/imm32/no-r32
32738     0/imm32/no-imm32
32739     0/imm32/no-imm8
32740     0/imm32/no-disp32
32741     1/imm32/xm32-is-first-inout
32742     3/imm32/x32-is-first-output
32743     0x11/imm32/alloc-id:fake
32744     _Primitive-max-xreg-with-mem/imm32/next
32745 _Primitive-max-xreg-with-mem:  # (payload primitive)
32746     0x11/imm32/alloc-id:fake:payload
32747     # var1/xreg <- divide var2 => f3 0f 5f/max var2/xm32 var1/x32
32748     0x11/imm32/alloc-id:fake
32749     _string-max/imm32/name
32750     0x11/imm32/alloc-id:fake
32751     Single-float-var-in-mem/imm32/inouts
32752     0x11/imm32/alloc-id:fake
32753     Single-float-var-in-some-register/imm32/outputs
32754     0x11/imm32/alloc-id:fake
32755     _string_f3_0f_5f_max/imm32/subx-name
32756     0/imm32/no-rm32
32757     0/imm32/no-r32
32758     0/imm32/no-imm32
32759     0/imm32/no-imm8
32760     0/imm32/no-disp32
32761     1/imm32/xm32-is-first-inout
32762     3/imm32/x32-is-first-output
32763     0x11/imm32/alloc-id:fake
32764     _Primitive-min-xreg-with-xreg/imm32/next
32765 # - floating-point minimum
32766 _Primitive-min-xreg-with-xreg:  # (payload primitive)
32767     0x11/imm32/alloc-id:fake:payload
32768     # var1/xreg <- divide var2 => f3 0f 5d/min var2/xm32 var1/x32
32769     0x11/imm32/alloc-id:fake
32770     _string-min/imm32/name
32771     0x11/imm32/alloc-id:fake
32772     Single-float-var-in-some-register/imm32/inouts
32773     0x11/imm32/alloc-id:fake
32774     Single-float-var-in-some-register/imm32/outputs
32775     0x11/imm32/alloc-id:fake
32776     _string_f3_0f_5d_min/imm32/subx-name
32777     0/imm32/no-rm32
32778     0/imm32/no-r32
32779     0/imm32/no-imm32
32780     0/imm32/no-imm8
32781     0/imm32/no-disp32
32782     1/imm32/xm32-is-first-inout
32783     3/imm32/x32-is-first-output
32784     0x11/imm32/alloc-id:fake
32785     _Primitive-min-xreg-with-mem/imm32/next
32786 _Primitive-min-xreg-with-mem:  # (payload primitive)
32787     0x11/imm32/alloc-id:fake:payload
32788     # var1/xreg <- divide var2 => f3 0f 5d/min var2/xm32 var1/x32
32789     0x11/imm32/alloc-id:fake
32790     _string-min/imm32/name
32791     0x11/imm32/alloc-id:fake
32792     Single-float-var-in-mem/imm32/inouts
32793     0x11/imm32/alloc-id:fake
32794     Single-float-var-in-some-register/imm32/outputs
32795     0x11/imm32/alloc-id:fake
32796     _string_f3_0f_5d_min/imm32/subx-name
32797     0/imm32/no-rm32
32798     0/imm32/no-r32
32799     0/imm32/no-imm32
32800     0/imm32/no-imm8
32801     0/imm32/no-disp32
32802     1/imm32/xm32-is-first-inout
32803     3/imm32/x32-is-first-output
32804     0x11/imm32/alloc-id:fake
32805     _Primitive-reciprocal-xreg-to-xreg/imm32/next
32806 # - floating-point reciprocal
32807 _Primitive-reciprocal-xreg-to-xreg:  # (payload primitive)
32808     0x11/imm32/alloc-id:fake:payload
32809     # var1/xreg <- reciprocal var2 => f3 0f 53/reciprocal var2/xm32 var1/x32
32810     0x11/imm32/alloc-id:fake
32811     _string-reciprocal/imm32/name
32812     0x11/imm32/alloc-id:fake
32813     Single-float-var-in-some-register/imm32/inouts
32814     0x11/imm32/alloc-id:fake
32815     Single-float-var-in-some-register/imm32/outputs
32816     0x11/imm32/alloc-id:fake
32817     _string_f3_0f_53_reciprocal/imm32/subx-name
32818     0/imm32/no-rm32
32819     0/imm32/no-r32
32820     0/imm32/no-imm32
32821     0/imm32/no-imm8
32822     0/imm32/no-disp32
32823     1/imm32/xm32-is-first-inout
32824     3/imm32/x32-is-first-output
32825     0x11/imm32/alloc-id:fake
32826     _Primitive-reciprocal-mem-to-xreg/imm32/next
32827 _Primitive-reciprocal-mem-to-xreg:  # (payload primitive)
32828     0x11/imm32/alloc-id:fake:payload
32829     # var1/xreg <- divide var2 => f3 0f 53/reciprocal var2/xm32 var1/x32
32830     0x11/imm32/alloc-id:fake
32831     _string-reciprocal/imm32/name
32832     0x11/imm32/alloc-id:fake
32833     Single-float-var-in-mem/imm32/inouts
32834     0x11/imm32/alloc-id:fake
32835     Single-float-var-in-some-register/imm32/outputs
32836     0x11/imm32/alloc-id:fake
32837     _string_f3_0f_53_reciprocal/imm32/subx-name
32838     0/imm32/no-rm32
32839     0/imm32/no-r32
32840     0/imm32/no-imm32
32841     0/imm32/no-imm8
32842     0/imm32/no-disp32
32843     1/imm32/xm32-is-first-inout
32844     3/imm32/x32-is-first-output
32845     0x11/imm32/alloc-id:fake
32846     _Primitive-square-root-xreg-to-xreg/imm32/next
32847 # - floating-point square root
32848 _Primitive-square-root-xreg-to-xreg:  # (payload primitive)
32849     0x11/imm32/alloc-id:fake:payload
32850     # var1/xreg <- square-root var2 => f3 0f 51/square-root var2/xm32 var1/x32
32851     0x11/imm32/alloc-id:fake
32852     _string-square-root/imm32/name
32853     0x11/imm32/alloc-id:fake
32854     Single-float-var-in-some-register/imm32/inouts
32855     0x11/imm32/alloc-id:fake
32856     Single-float-var-in-some-register/imm32/outputs
32857     0x11/imm32/alloc-id:fake
32858     _string_f3_0f_51_square_root/imm32/subx-name
32859     0/imm32/no-rm32
32860     0/imm32/no-r32
32861     0/imm32/no-imm32
32862     0/imm32/no-imm8
32863     0/imm32/no-disp32
32864     1/imm32/xm32-is-first-inout
32865     3/imm32/x32-is-first-output
32866     0x11/imm32/alloc-id:fake
32867     _Primitive-square-root-mem-to-xreg/imm32/next
32868 _Primitive-square-root-mem-to-xreg:  # (payload primitive)
32869     0x11/imm32/alloc-id:fake:payload
32870     # var1/xreg <- divide var2 => f3 0f 51/square-root var2/xm32 var1/x32
32871     0x11/imm32/alloc-id:fake
32872     _string-square-root/imm32/name
32873     0x11/imm32/alloc-id:fake
32874     Single-float-var-in-mem/imm32/inouts
32875     0x11/imm32/alloc-id:fake
32876     Single-float-var-in-some-register/imm32/outputs
32877     0x11/imm32/alloc-id:fake
32878     _string_f3_0f_51_square_root/imm32/subx-name
32879     0/imm32/no-rm32
32880     0/imm32/no-r32
32881     0/imm32/no-imm32
32882     0/imm32/no-imm8
32883     0/imm32/no-disp32
32884     1/imm32/xm32-is-first-inout
32885     3/imm32/x32-is-first-output
32886     0x11/imm32/alloc-id:fake
32887     _Primitive-inverse-square-root-xreg-to-xreg/imm32/next
32888 # - floating-point inverse square root 1/sqrt(x)
32889 _Primitive-inverse-square-root-xreg-to-xreg:  # (payload primitive)
32890     0x11/imm32/alloc-id:fake:payload
32891     # var1/xreg <- reciprocal var2 => f3 0f 52/inverse-square-root var2/xm32 var1/x32
32892     0x11/imm32/alloc-id:fake
32893     _string-inverse-square-root/imm32/name
32894     0x11/imm32/alloc-id:fake
32895     Single-float-var-in-some-register/imm32/inouts
32896     0x11/imm32/alloc-id:fake
32897     Single-float-var-in-some-register/imm32/outputs
32898     0x11/imm32/alloc-id:fake
32899     _string_f3_0f_52_inverse_square_root/imm32/subx-name
32900     0/imm32/no-rm32
32901     0/imm32/no-r32
32902     0/imm32/no-imm32
32903     0/imm32/no-imm8
32904     0/imm32/no-disp32
32905     1/imm32/xm32-is-first-inout
32906     3/imm32/x32-is-first-output
32907     0x11/imm32/alloc-id:fake
32908     _Primitive-inverse-square-root-mem-to-xreg/imm32/next
32909 _Primitive-inverse-square-root-mem-to-xreg:  # (payload primitive)
32910     0x11/imm32/alloc-id:fake:payload
32911     # var1/xreg <- divide var2 => f3 0f 52/inverse-square-root var2/xm32 var1/x32
32912     0x11/imm32/alloc-id:fake
32913     _string-inverse-square-root/imm32/name
32914     0x11/imm32/alloc-id:fake
32915     Single-float-var-in-mem/imm32/inouts
32916     0x11/imm32/alloc-id:fake
32917     Single-float-var-in-some-register/imm32/outputs
32918     0x11/imm32/alloc-id:fake
32919     _string_f3_0f_52_inverse_square_root/imm32/subx-name
32920     0/imm32/no-rm32
32921     0/imm32/no-r32
32922     0/imm32/no-imm32
32923     0/imm32/no-imm8
32924     0/imm32/no-disp32
32925     1/imm32/xm32-is-first-inout
32926     3/imm32/x32-is-first-output
32927     0x11/imm32/alloc-id:fake
32928     _Primitive-compare-xreg-with-xreg/imm32/next
32929 # - floating-point compare
32930 _Primitive-compare-xreg-with-xreg:  # (payload primitive)
32931     0x11/imm32/alloc-id:fake:payload
32932     # compare var1/reg1 var2/reg2 => 0f 2f/compare var2/x32 var1/xm32
32933     0x11/imm32/alloc-id:fake
32934     _string-compare/imm32/name
32935     0x11/imm32/alloc-id:fake
32936     Two-float-args-in-regs/imm32/inouts
32937     0/imm32/no-outputs
32938     0/imm32/no-outputs
32939     0x11/imm32/alloc-id:fake
32940     _string_0f_2f_compare/imm32/subx-name
32941     0/imm32/no-rm32
32942     0/imm32/no-r32
32943     0/imm32/no-imm32
32944     0/imm32/no-imm8
32945     0/imm32/no-disp32
32946     2/imm32/xm32-is-second-inout
32947     1/imm32/x32-is-first-inout
32948     0x11/imm32/alloc-id:fake
32949     _Primitive-compare-xreg-with-mem/imm32/next
32950 _Primitive-compare-xreg-with-mem:  # (payload primitive)
32951     0x11/imm32/alloc-id:fake:payload
32952     # compare var1/xreg var2 => 0f 2f/compare var1/x32 var2/xm32
32953     0x11/imm32/alloc-id:fake
32954     _string-compare/imm32/name
32955     0x11/imm32/alloc-id:fake
32956     Two-args-float-reg-float-stack/imm32/inouts
32957     0/imm32/no-outputs
32958     0/imm32/no-outputs
32959     0x11/imm32/alloc-id:fake
32960     _string_0f_2f_compare/imm32/subx-name
32961     0/imm32/no-rm32
32962     0/imm32/no-r32
32963     0/imm32/no-imm32
32964     0/imm32/no-imm8
32965     0/imm32/no-disp32
32966     2/imm32/xm32-is-second-inout
32967     1/imm32/x32-is-first-inout
32968     0x11/imm32/alloc-id:fake
32969     _Primitive-break-if-addr</imm32/next
32970 # - branches
32971 _Primitive-break-if-addr<:  # (payload primitive)
32972     0x11/imm32/alloc-id:fake:payload
32973     0x11/imm32/alloc-id:fake
32974     _string-break-if-addr</imm32/name
32975     0/imm32/no-inouts
32976     0/imm32/no-inouts
32977     0/imm32/no-outputs
32978     0/imm32/no-outputs
32979     0x11/imm32/alloc-id:fake
32980     _string_0f_82_jump_break/imm32/subx-name
32981     0/imm32/no-rm32
32982     0/imm32/no-r32
32983     0/imm32/no-imm32
32984     0/imm32/no-imm8
32985     0/imm32/no-disp32
32986     0/imm32/no-xm32
32987     0/imm32/no-x32
32988     0x11/imm32/alloc-id:fake
32989     _Primitive-break-if-addr>=/imm32/next
32990 _Primitive-break-if-addr>=:  # (payload primitive)
32991     0x11/imm32/alloc-id:fake:payload
32992     0x11/imm32/alloc-id:fake
32993     _string-break-if-addr>=/imm32/name
32994     0/imm32/no-inouts
32995     0/imm32/no-inouts
32996     0/imm32/no-outputs
32997     0/imm32/no-outputs
32998     0x11/imm32/alloc-id:fake
32999     _string_0f_83_jump_break/imm32/subx-name
33000     0/imm32/no-rm32
33001     0/imm32/no-r32
33002     0/imm32/no-imm32
33003     0/imm32/no-imm8
33004     0/imm32/no-disp32
33005     0/imm32/no-xm32
33006     0/imm32/no-x32
33007     0x11/imm32/alloc-id:fake
33008     _Primitive-break-if-=/imm32/next
33009 _Primitive-break-if-=:  # (payload primitive)
33010     0x11/imm32/alloc-id:fake:payload
33011     0x11/imm32/alloc-id:fake
33012     _string-break-if-=/imm32/name
33013     0/imm32/no-inouts
33014     0/imm32/no-inouts
33015     0/imm32/no-outputs
33016     0/imm32/no-outputs
33017     0x11/imm32/alloc-id:fake
33018     _string_0f_84_jump_break/imm32/subx-name
33019     0/imm32/no-rm32
33020     0/imm32/no-r32
33021     0/imm32/no-imm32
33022     0/imm32/no-imm8
33023     0/imm32/no-disp32
33024     0/imm32/no-xm32
33025     0/imm32/no-x32
33026     0x11/imm32/alloc-id:fake
33027     _Primitive-break-if-!=/imm32/next
33028 _Primitive-break-if-!=:  # (payload primitive)
33029     0x11/imm32/alloc-id:fake:payload
33030     0x11/imm32/alloc-id:fake
33031     _string-break-if-!=/imm32/name
33032     0/imm32/no-inouts
33033     0/imm32/no-inouts
33034     0/imm32/no-outputs
33035     0/imm32/no-outputs
33036     0x11/imm32/alloc-id:fake
33037     _string_0f_85_jump_break/imm32/subx-name
33038     0/imm32/no-rm32
33039     0/imm32/no-r32
33040     0/imm32/no-imm32
33041     0/imm32/no-imm8
33042     0/imm32/no-disp32
33043     0/imm32/no-xm32
33044     0/imm32/no-x32
33045     0x11/imm32/alloc-id:fake
33046     _Primitive-break-if-addr<=/imm32/next
33047 _Primitive-break-if-addr<=:  # (payload primitive)
33048     0x11/imm32/alloc-id:fake:payload
33049     0x11/imm32/alloc-id:fake
33050     _string-break-if-addr<=/imm32/name
33051     0/imm32/no-inouts
33052     0/imm32/no-inouts
33053     0/imm32/no-outputs
33054     0/imm32/no-outputs
33055     0x11/imm32/alloc-id:fake
33056     _string_0f_86_jump_break/imm32/subx-name
33057     0/imm32/no-rm32
33058     0/imm32/no-r32
33059     0/imm32/no-imm32
33060     0/imm32/no-imm8
33061     0/imm32/no-disp32
33062     0/imm32/no-xm32
33063     0/imm32/no-x32
33064     0x11/imm32/alloc-id:fake
33065     _Primitive-break-if-addr>/imm32/next
33066 _Primitive-break-if-addr>:  # (payload primitive)
33067     0x11/imm32/alloc-id:fake:payload
33068     0x11/imm32/alloc-id:fake
33069     _string-break-if-addr>/imm32/name
33070     0/imm32/no-inouts
33071     0/imm32/no-inouts
33072     0/imm32/no-outputs
33073     0/imm32/no-outputs
33074     0x11/imm32/alloc-id:fake
33075     _string_0f_87_jump_break/imm32/subx-name
33076     0/imm32/no-rm32
33077     0/imm32/no-r32
33078     0/imm32/no-imm32
33079     0/imm32/no-imm8
33080     0/imm32/no-disp32
33081     0/imm32/no-xm32
33082     0/imm32/no-x32
33083     0x11/imm32/alloc-id:fake
33084     _Primitive-break-if-</imm32/next
33085 _Primitive-break-if-<:  # (payload primitive)
33086     0x11/imm32/alloc-id:fake:payload
33087     0x11/imm32/alloc-id:fake
33088     _string-break-if-</imm32/name
33089     0/imm32/no-inouts
33090     0/imm32/no-inouts
33091     0/imm32/no-outputs
33092     0/imm32/no-outputs
33093     0x11/imm32/alloc-id:fake
33094     _string_0f_8c_jump_break/imm32/subx-name
33095     0/imm32/no-rm32
33096     0/imm32/no-r32
33097     0/imm32/no-imm32
33098     0/imm32/no-imm8
33099     0/imm32/no-disp32
33100     0/imm32/no-xm32
33101     0/imm32/no-x32
33102     0x11/imm32/alloc-id:fake
33103     _Primitive-break-if->=/imm32/next
33104 _Primitive-break-if->=:  # (payload primitive)
33105     0x11/imm32/alloc-id:fake:payload
33106     0x11/imm32/alloc-id:fake
33107     _string-break-if->=/imm32/name
33108     0/imm32/no-inouts
33109     0/imm32/no-inouts
33110     0/imm32/no-outputs
33111     0/imm32/no-outputs
33112     0x11/imm32/alloc-id:fake
33113     _string_0f_8d_jump_break/imm32/subx-name
33114     0/imm32/no-rm32
33115     0/imm32/no-r32
33116     0/imm32/no-imm32
33117     0/imm32/no-imm8
33118     0/imm32/no-disp32
33119     0/imm32/no-xm32
33120     0/imm32/no-x32
33121     0x11/imm32/alloc-id:fake
33122     _Primitive-break-if-<=/imm32/next
33123 _Primitive-break-if-<=:  # (payload primitive)
33124     0x11/imm32/alloc-id:fake:payload
33125     0x11/imm32/alloc-id:fake
33126     _string-break-if-<=/imm32/name
33127     0/imm32/no-inouts
33128     0/imm32/no-inouts
33129     0/imm32/no-outputs
33130     0/imm32/no-outputs
33131     0x11/imm32/alloc-id:fake
33132     _string_0f_8e_jump_break/imm32/subx-name
33133     0/imm32/no-rm32
33134     0/imm32/no-r32
33135     0/imm32/no-imm32
33136     0/imm32/no-imm8
33137     0/imm32/no-disp32
33138     0/imm32/no-xm32
33139     0/imm32/no-x32
33140     0x11/imm32/alloc-id:fake
33141     _Primitive-break-if->/imm32/next
33142 _Primitive-break-if->:  # (payload primitive)
33143     0x11/imm32/alloc-id:fake:payload
33144     0x11/imm32/alloc-id:fake
33145     _string-break-if->/imm32/name
33146     0/imm32/no-inouts
33147     0/imm32/no-inouts
33148     0/imm32/no-outputs
33149     0/imm32/no-outputs
33150     0x11/imm32/alloc-id:fake
33151     _string_0f_8f_jump_break/imm32/subx-name
33152     0/imm32/no-rm32
33153     0/imm32/no-r32
33154     0/imm32/no-imm32
33155     0/imm32/no-imm8
33156     0/imm32/no-disp32
33157     0/imm32/no-xm32
33158     0/imm32/no-x32
33159     0x11/imm32/alloc-id:fake
33160     _Primitive-break-if-carry/imm32/next
33161 _Primitive-break-if-carry:  # (payload primitive)
33162     0x11/imm32/alloc-id:fake:payload
33163     0x11/imm32/alloc-id:fake
33164     _string-break-if-carry/imm32/name
33165     0/imm32/no-inouts
33166     0/imm32/no-inouts
33167     0/imm32/no-outputs
33168     0/imm32/no-outputs
33169     0x11/imm32/alloc-id:fake
33170     _string_0f_82_jump_break/imm32/subx-name
33171     0/imm32/no-rm32
33172     0/imm32/no-r32
33173     0/imm32/no-imm32
33174     0/imm32/no-imm8
33175     0/imm32/no-disp32
33176     0/imm32/no-xm32
33177     0/imm32/no-x32
33178     0x11/imm32/alloc-id:fake
33179     _Primitive-break-if-not-carry/imm32/next
33180 _Primitive-break-if-not-carry:  # (payload primitive)
33181     0x11/imm32/alloc-id:fake:payload
33182     0x11/imm32/alloc-id:fake
33183     _string-break-if-not-carry/imm32/name
33184     0/imm32/no-inouts
33185     0/imm32/no-inouts
33186     0/imm32/no-outputs
33187     0/imm32/no-outputs
33188     0x11/imm32/alloc-id:fake
33189     _string_0f_83_jump_break/imm32/subx-name
33190     0/imm32/no-rm32
33191     0/imm32/no-r32
33192     0/imm32/no-imm32
33193     0/imm32/no-imm8
33194     0/imm32/no-disp32
33195     0/imm32/no-xm32
33196     0/imm32/no-x32
33197     0x11/imm32/alloc-id:fake
33198     _Primitive-break-if-overflow/imm32/next
33199 _Primitive-break-if-overflow:  # (payload primitive)
33200     0x11/imm32/alloc-id:fake:payload
33201     0x11/imm32/alloc-id:fake
33202     _string-break-if-overflow/imm32/name
33203     0/imm32/no-inouts
33204     0/imm32/no-inouts
33205     0/imm32/no-outputs
33206     0/imm32/no-outputs
33207     0x11/imm32/alloc-id:fake
33208     _string_0f_80_jump_break/imm32/subx-name
33209     0/imm32/no-rm32
33210     0/imm32/no-r32
33211     0/imm32/no-imm32
33212     0/imm32/no-imm8
33213     0/imm32/no-disp32
33214     0/imm32/no-xm32
33215     0/imm32/no-x32
33216     0x11/imm32/alloc-id:fake
33217     _Primitive-break-if-not-overflow/imm32/next
33218 _Primitive-break-if-not-overflow:  # (payload primitive)
33219     0x11/imm32/alloc-id:fake:payload
33220     0x11/imm32/alloc-id:fake
33221     _string-break-if-not-overflow/imm32/name
33222     0/imm32/no-inouts
33223     0/imm32/no-inouts
33224     0/imm32/no-outputs
33225     0/imm32/no-outputs
33226     0x11/imm32/alloc-id:fake
33227     _string_0f_81_jump_break/imm32/subx-name
33228     0/imm32/no-rm32
33229     0/imm32/no-r32
33230     0/imm32/no-imm32
33231     0/imm32/no-imm8
33232     0/imm32/no-disp32
33233     0/imm32/no-xm32
33234     0/imm32/no-x32
33235     0x11/imm32/alloc-id:fake
33236     _Primitive-break/imm32/next
33237 _Primitive-break:  # (payload primitive)
33238     0x11/imm32/alloc-id:fake:payload
33239     0x11/imm32/alloc-id:fake
33240     _string-break/imm32/name
33241     0/imm32/no-inouts
33242     0/imm32/no-inouts
33243     0/imm32/no-outputs
33244     0/imm32/no-outputs
33245     0x11/imm32/alloc-id:fake
33246     _string_e9_jump_break/imm32/subx-name
33247     0/imm32/no-rm32
33248     0/imm32/no-r32
33249     0/imm32/no-imm32
33250     0/imm32/no-imm8
33251     0/imm32/no-disp32
33252     0/imm32/no-xm32
33253     0/imm32/no-x32
33254     0x11/imm32/alloc-id:fake
33255     _Primitive-loop-if-addr</imm32/next
33256 _Primitive-loop-if-addr<:  # (payload primitive)
33257     0x11/imm32/alloc-id:fake:payload
33258     0x11/imm32/alloc-id:fake
33259     _string-loop-if-addr</imm32/name
33260     0/imm32/no-inouts
33261     0/imm32/no-inouts
33262     0/imm32/no-outputs
33263     0/imm32/no-outputs
33264     0x11/imm32/alloc-id:fake
33265     _string_0f_82_jump_loop/imm32/subx-name
33266     0/imm32/no-rm32
33267     0/imm32/no-r32
33268     0/imm32/no-imm32
33269     0/imm32/no-imm8
33270     0/imm32/no-disp32
33271     0/imm32/no-xm32
33272     0/imm32/no-x32
33273     0x11/imm32/alloc-id:fake
33274     _Primitive-loop-if-addr>=/imm32/next
33275 _Primitive-loop-if-addr>=:  # (payload primitive)
33276     0x11/imm32/alloc-id:fake:payload
33277     0x11/imm32/alloc-id:fake
33278     _string-loop-if-addr>=/imm32/name
33279     0/imm32/no-inouts
33280     0/imm32/no-inouts
33281     0/imm32/no-outputs
33282     0/imm32/no-outputs
33283     0x11/imm32/alloc-id:fake
33284     _string_0f_83_jump_loop/imm32/subx-name
33285     0/imm32/no-rm32
33286     0/imm32/no-r32
33287     0/imm32/no-imm32
33288     0/imm32/no-imm8
33289     0/imm32/no-disp32
33290     0/imm32/no-xm32
33291     0/imm32/no-x32
33292     0x11/imm32/alloc-id:fake
33293     _Primitive-loop-if-=/imm32/next
33294 _Primitive-loop-if-=:  # (payload primitive)
33295     0x11/imm32/alloc-id:fake:payload
33296     0x11/imm32/alloc-id:fake
33297     _string-loop-if-=/imm32/name
33298     0/imm32/no-inouts
33299     0/imm32/no-inouts
33300     0/imm32/no-outputs
33301     0/imm32/no-outputs
33302     0x11/imm32/alloc-id:fake
33303     _string_0f_84_jump_loop/imm32/subx-name
33304     0/imm32/no-rm32
33305     0/imm32/no-r32
33306     0/imm32/no-imm32
33307     0/imm32/no-imm8
33308     0/imm32/no-disp32
33309     0/imm32/no-xm32
33310     0/imm32/no-x32
33311     0x11/imm32/alloc-id:fake
33312     _Primitive-loop-if-!=/imm32/next
33313 _Primitive-loop-if-!=:  # (payload primitive)
33314     0x11/imm32/alloc-id:fake:payload
33315     0x11/imm32/alloc-id:fake
33316     _string-loop-if-!=/imm32/name
33317     0/imm32/no-inouts
33318     0/imm32/no-inouts
33319     0/imm32/no-outputs
33320     0/imm32/no-outputs
33321     0x11/imm32/alloc-id:fake
33322     _string_0f_85_jump_loop/imm32/subx-name
33323     0/imm32/no-rm32
33324     0/imm32/no-r32
33325     0/imm32/no-imm32
33326     0/imm32/no-imm8
33327     0/imm32/no-disp32
33328     0/imm32/no-xm32
33329     0/imm32/no-x32
33330     0x11/imm32/alloc-id:fake
33331     _Primitive-loop-if-addr<=/imm32/next
33332 _Primitive-loop-if-addr<=:  # (payload primitive)
33333     0x11/imm32/alloc-id:fake:payload
33334     0x11/imm32/alloc-id:fake
33335     _string-loop-if-addr<=/imm32/name
33336     0/imm32/no-inouts
33337     0/imm32/no-inouts
33338     0/imm32/no-outputs
33339     0/imm32/no-outputs
33340     0x11/imm32/alloc-id:fake
33341     _string_0f_86_jump_loop/imm32/subx-name
33342     0/imm32/no-rm32
33343     0/imm32/no-r32
33344     0/imm32/no-imm32
33345     0/imm32/no-imm8
33346     0/imm32/no-disp32
33347     0/imm32/no-xm32
33348     0/imm32/no-x32
33349     0x11/imm32/alloc-id:fake
33350     _Primitive-loop-if-addr>/imm32/next
33351 _Primitive-loop-if-addr>:  # (payload primitive)
33352     0x11/imm32/alloc-id:fake:payload
33353     0x11/imm32/alloc-id:fake
33354     _string-loop-if-addr>/imm32/name
33355     0/imm32/no-inouts
33356     0/imm32/no-inouts
33357     0/imm32/no-outputs
33358     0/imm32/no-outputs
33359     0x11/imm32/alloc-id:fake
33360     _string_0f_87_jump_loop/imm32/subx-name
33361     0/imm32/no-rm32
33362     0/imm32/no-r32
33363     0/imm32/no-imm32
33364     0/imm32/no-imm8
33365     0/imm32/no-disp32
33366     0/imm32/no-xm32
33367     0/imm32/no-x32
33368     0x11/imm32/alloc-id:fake
33369     _Primitive-loop-if-</imm32/next
33370 _Primitive-loop-if-<:  # (payload primitive)
33371     0x11/imm32/alloc-id:fake:payload
33372     0x11/imm32/alloc-id:fake
33373     _string-loop-if-</imm32/name
33374     0/imm32/no-inouts
33375     0/imm32/no-inouts
33376     0/imm32/no-outputs
33377     0/imm32/no-outputs
33378     0x11/imm32/alloc-id:fake
33379     _string_0f_8c_jump_loop/imm32/subx-name
33380     0/imm32/no-rm32
33381     0/imm32/no-r32
33382     0/imm32/no-imm32
33383     0/imm32/no-imm8
33384     0/imm32/no-disp32
33385     0/imm32/no-xm32
33386     0/imm32/no-x32
33387     0x11/imm32/alloc-id:fake
33388     _Primitive-loop-if->=/imm32/next
33389 _Primitive-loop-if->=:  # (payload primitive)
33390     0x11/imm32/alloc-id:fake:payload
33391     0x11/imm32/alloc-id:fake
33392     _string-loop-if->=/imm32/name
33393     0/imm32/no-inouts
33394     0/imm32/no-inouts
33395     0/imm32/no-outputs
33396     0/imm32/no-outputs
33397     0x11/imm32/alloc-id:fake
33398     _string_0f_8d_jump_loop/imm32/subx-name
33399     0/imm32/no-rm32
33400     0/imm32/no-r32
33401     0/imm32/no-imm32
33402     0/imm32/no-imm8
33403     0/imm32/no-disp32
33404     0/imm32/no-xm32
33405     0/imm32/no-x32
33406     0x11/imm32/alloc-id:fake
33407     _Primitive-loop-if-<=/imm32/next
33408 _Primitive-loop-if-<=:  # (payload primitive)
33409     0x11/imm32/alloc-id:fake:payload
33410     0x11/imm32/alloc-id:fake
33411     _string-loop-if-<=/imm32/name
33412     0/imm32/no-inouts
33413     0/imm32/no-inouts
33414     0/imm32/no-outputs
33415     0/imm32/no-outputs
33416     0x11/imm32/alloc-id:fake
33417     _string_0f_8e_jump_loop/imm32/subx-name
33418     0/imm32/no-rm32
33419     0/imm32/no-r32
33420     0/imm32/no-imm32
33421     0/imm32/no-imm8
33422     0/imm32/no-disp32
33423     0/imm32/no-xm32
33424     0/imm32/no-x32
33425     0x11/imm32/alloc-id:fake
33426     _Primitive-loop-if->/imm32/next
33427 _Primitive-loop-if->:  # (payload primitive)
33428     0x11/imm32/alloc-id:fake:payload
33429     0x11/imm32/alloc-id:fake
33430     _string-loop-if->/imm32/name
33431     0/imm32/no-inouts
33432     0/imm32/no-inouts
33433     0/imm32/no-outputs
33434     0/imm32/no-outputs
33435     0x11/imm32/alloc-id:fake
33436     _string_0f_8f_jump_loop/imm32/subx-name
33437     0/imm32/no-rm32
33438     0/imm32/no-r32
33439     0/imm32/no-imm32
33440     0/imm32/no-imm8
33441     0/imm32/no-disp32
33442     0/imm32/no-xm32
33443     0/imm32/no-x32
33444     0x11/imm32/alloc-id:fake
33445     _Primitive-loop-if-carry/imm32/next
33446 _Primitive-loop-if-carry:  # (payload primitive)
33447     0x11/imm32/alloc-id:fake:payload
33448     0x11/imm32/alloc-id:fake
33449     _string-loop-if-carry/imm32/name
33450     0/imm32/no-inouts
33451     0/imm32/no-inouts
33452     0/imm32/no-outputs
33453     0/imm32/no-outputs
33454     0x11/imm32/alloc-id:fake
33455     _string_0f_82_jump_loop/imm32/subx-name
33456     0/imm32/no-rm32
33457     0/imm32/no-r32
33458     0/imm32/no-imm32
33459     0/imm32/no-imm8
33460     0/imm32/no-disp32
33461     0/imm32/no-xm32
33462     0/imm32/no-x32
33463     0x11/imm32/alloc-id:fake
33464     _Primitive-loop-if-not-carry/imm32/next
33465 _Primitive-loop-if-not-carry:  # (payload primitive)
33466     0x11/imm32/alloc-id:fake:payload
33467     0x11/imm32/alloc-id:fake
33468     _string-loop-if-not-carry/imm32/name
33469     0/imm32/no-inouts
33470     0/imm32/no-inouts
33471     0/imm32/no-outputs
33472     0/imm32/no-outputs
33473     0x11/imm32/alloc-id:fake
33474     _string_0f_83_jump_loop/imm32/subx-name
33475     0/imm32/no-rm32
33476     0/imm32/no-r32
33477     0/imm32/no-imm32
33478     0/imm32/no-imm8
33479     0/imm32/no-disp32
33480     0/imm32/no-xm32
33481     0/imm32/no-x32
33482     0x11/imm32/alloc-id:fake
33483     _Primitive-loop-if-overflow/imm32/next
33484 _Primitive-loop-if-overflow:  # (payload primitive)
33485     0x11/imm32/alloc-id:fake:payload
33486     0x11/imm32/alloc-id:fake
33487     _string-loop-if-overflow/imm32/name
33488     0/imm32/no-inouts
33489     0/imm32/no-inouts
33490     0/imm32/no-outputs
33491     0/imm32/no-outputs
33492     0x11/imm32/alloc-id:fake
33493     _string_0f_80_jump_loop/imm32/subx-name
33494     0/imm32/no-rm32
33495     0/imm32/no-r32
33496     0/imm32/no-imm32
33497     0/imm32/no-imm8
33498     0/imm32/no-disp32
33499     0/imm32/no-xm32
33500     0/imm32/no-x32
33501     0x11/imm32/alloc-id:fake
33502     _Primitive-loop-if-not-overflow/imm32/next
33503 _Primitive-loop-if-not-overflow:  # (payload primitive)
33504     0x11/imm32/alloc-id:fake:payload
33505     0x11/imm32/alloc-id:fake
33506     _string-loop-if-not-overflow/imm32/name
33507     0/imm32/no-inouts
33508     0/imm32/no-inouts
33509     0/imm32/no-outputs
33510     0/imm32/no-outputs
33511     0x11/imm32/alloc-id:fake
33512     _string_0f_81_jump_loop/imm32/subx-name
33513     0/imm32/no-rm32
33514     0/imm32/no-r32
33515     0/imm32/no-imm32
33516     0/imm32/no-imm8
33517     0/imm32/no-disp32
33518     0/imm32/no-xm32
33519     0/imm32/no-x32
33520     0x11/imm32/alloc-id:fake
33521     _Primitive-loop/imm32/next  # we probably don't need an unconditional break
33522 _Primitive-loop:  # (payload primitive)
33523     0x11/imm32/alloc-id:fake:payload
33524     0x11/imm32/alloc-id:fake
33525     _string-loop/imm32/name
33526     0/imm32/no-inouts
33527     0/imm32/no-inouts
33528     0/imm32/no-outputs
33529     0/imm32/no-outputs
33530     0x11/imm32/alloc-id:fake
33531     _string_e9_jump_loop/imm32/subx-name
33532     0/imm32/no-rm32
33533     0/imm32/no-r32
33534     0/imm32/no-imm32
33535     0/imm32/no-imm8
33536     0/imm32/no-disp32
33537     0/imm32/no-xm32
33538     0/imm32/no-x32
33539     0x11/imm32/alloc-id:fake
33540     _Primitive-break-if-addr<-named/imm32/next
33541 # - branches to named blocks
33542 _Primitive-break-if-addr<-named:  # (payload primitive)
33543     0x11/imm32/alloc-id:fake:payload
33544     0x11/imm32/alloc-id:fake
33545     _string-break-if-addr</imm32/name
33546     0x11/imm32/alloc-id:fake
33547     Single-lit-var/imm32/inouts
33548     0/imm32/no-outputs
33549     0/imm32/no-outputs
33550     0x11/imm32/alloc-id:fake
33551     _string_0f_82_jump_label/imm32/subx-name
33552     0/imm32/no-rm32
33553     0/imm32/no-r32
33554     0/imm32/no-imm32
33555     0/imm32/no-imm8
33556     1/imm32/disp32-is-first-inout
33557     0/imm32/no-xm32
33558     0/imm32/no-x32
33559     0x11/imm32/alloc-id:fake
33560     _Primitive-break-if-addr>=-named/imm32/next
33561 _Primitive-break-if-addr>=-named:  # (payload primitive)
33562     0x11/imm32/alloc-id:fake:payload
33563     0x11/imm32/alloc-id:fake
33564     _string-break-if-addr>=/imm32/name
33565     0x11/imm32/alloc-id:fake
33566     Single-lit-var/imm32/inouts
33567     0/imm32/no-outputs
33568     0/imm32/no-outputs
33569     0x11/imm32/alloc-id:fake
33570     _string_0f_83_jump_label/imm32/subx-name
33571     0/imm32/no-rm32
33572     0/imm32/no-r32
33573     0/imm32/no-imm32
33574     0/imm32/no-imm8
33575     1/imm32/disp32-is-first-inout
33576     0/imm32/no-xm32
33577     0/imm32/no-x32
33578     0x11/imm32/alloc-id:fake
33579     _Primitive-break-if-=-named/imm32/next
33580 _Primitive-break-if-=-named:  # (payload primitive)
33581     0x11/imm32/alloc-id:fake:payload
33582     0x11/imm32/alloc-id:fake
33583     _string-break-if-=/imm32/name
33584     0x11/imm32/alloc-id:fake
33585     Single-lit-var/imm32/inouts
33586     0/imm32/no-outputs
33587     0/imm32/no-outputs
33588     0x11/imm32/alloc-id:fake
33589     _string_0f_84_jump_label/imm32/subx-name
33590     0/imm32/no-rm32
33591     0/imm32/no-r32
33592     0/imm32/no-imm32
33593     0/imm32/no-imm8
33594     1/imm32/disp32-is-first-inout
33595     0/imm32/no-xm32
33596     0/imm32/no-x32
33597     0x11/imm32/alloc-id:fake
33598     _Primitive-break-if-!=-named/imm32/next
33599 _Primitive-break-if-!=-named:  # (payload primitive)
33600     0x11/imm32/alloc-id:fake:payload
33601     0x11/imm32/alloc-id:fake
33602     _string-break-if-!=/imm32/name
33603     0x11/imm32/alloc-id:fake
33604     Single-lit-var/imm32/inouts
33605     0/imm32/no-outputs
33606     0/imm32/no-outputs
33607     0x11/imm32/alloc-id:fake
33608     _string_0f_85_jump_label/imm32/subx-name
33609     0/imm32/no-rm32
33610     0/imm32/no-r32
33611     0/imm32/no-imm32
33612     0/imm32/no-imm8
33613     1/imm32/disp32-is-first-inout
33614     0/imm32/no-xm32
33615     0/imm32/no-x32
33616     0x11/imm32/alloc-id:fake
33617     _Primitive-break-if-addr<=-named/imm32/next
33618 _Primitive-break-if-addr<=-named:  # (payload primitive)
33619     0x11/imm32/alloc-id:fake:payload
33620     0x11/imm32/alloc-id:fake
33621     _string-break-if-addr<=/imm32/name
33622     0x11/imm32/alloc-id:fake
33623     Single-lit-var/imm32/inouts
33624     0/imm32/no-outputs
33625     0/imm32/no-outputs
33626     0x11/imm32/alloc-id:fake
33627     _string_0f_86_jump_label/imm32/subx-name
33628     0/imm32/no-rm32
33629     0/imm32/no-r32
33630     0/imm32/no-imm32
33631     0/imm32/no-imm8
33632     1/imm32/disp32-is-first-inout
33633     0/imm32/no-xm32
33634     0/imm32/no-x32
33635     0x11/imm32/alloc-id:fake
33636     _Primitive-break-if-addr>-named/imm32/next
33637 _Primitive-break-if-addr>-named:  # (payload primitive)
33638     0x11/imm32/alloc-id:fake:payload
33639     0x11/imm32/alloc-id:fake
33640     _string-break-if-addr>/imm32/name
33641     0x11/imm32/alloc-id:fake
33642     Single-lit-var/imm32/inouts
33643     0/imm32/no-outputs
33644     0/imm32/no-outputs
33645     0x11/imm32/alloc-id:fake
33646     _string_0f_87_jump_label/imm32/subx-name
33647     0/imm32/no-rm32
33648     0/imm32/no-r32
33649     0/imm32/no-imm32
33650     0/imm32/no-imm8
33651     1/imm32/disp32-is-first-inout
33652     0/imm32/no-xm32
33653     0/imm32/no-x32
33654     0x11/imm32/alloc-id:fake
33655     _Primitive-break-if-<-named/imm32/next
33656 _Primitive-break-if-<-named:  # (payload primitive)
33657     0x11/imm32/alloc-id:fake:payload
33658     0x11/imm32/alloc-id:fake
33659     _string-break-if-</imm32/name
33660     0x11/imm32/alloc-id:fake
33661     Single-lit-var/imm32/inouts
33662     0/imm32/no-outputs
33663     0/imm32/no-outputs
33664     0x11/imm32/alloc-id:fake
33665     _string_0f_8c_jump_label/imm32/subx-name
33666     0/imm32/no-rm32
33667     0/imm32/no-r32
33668     0/imm32/no-imm32
33669     0/imm32/no-imm8
33670     1/imm32/disp32-is-first-inout
33671     0/imm32/no-xm32
33672     0/imm32/no-x32
33673     0x11/imm32/alloc-id:fake
33674     _Primitive-break-if->=-named/imm32/next
33675 _Primitive-break-if->=-named:  # (payload primitive)
33676     0x11/imm32/alloc-id:fake:payload
33677     0x11/imm32/alloc-id:fake
33678     _string-break-if->=/imm32/name
33679     0x11/imm32/alloc-id:fake
33680     Single-lit-var/imm32/inouts
33681     0/imm32/no-outputs
33682     0/imm32/no-outputs
33683     0x11/imm32/alloc-id:fake
33684     _string_0f_8d_jump_label/imm32/subx-name
33685     0/imm32/no-rm32
33686     0/imm32/no-r32
33687     0/imm32/no-imm32
33688     0/imm32/no-imm8
33689     1/imm32/disp32-is-first-inout
33690     0/imm32/no-xm32
33691     0/imm32/no-x32
33692     0x11/imm32/alloc-id:fake
33693     _Primitive-break-if-<=-named/imm32/next
33694 _Primitive-break-if-<=-named:  # (payload primitive)
33695     0x11/imm32/alloc-id:fake:payload
33696     0x11/imm32/alloc-id:fake
33697     _string-break-if-<=/imm32/name
33698     0x11/imm32/alloc-id:fake
33699     Single-lit-var/imm32/inouts
33700     0/imm32/no-outputs
33701     0/imm32/no-outputs
33702     0x11/imm32/alloc-id:fake
33703     _string_0f_8e_jump_label/imm32/subx-name
33704     0/imm32/no-rm32
33705     0/imm32/no-r32
33706     0/imm32/no-imm32
33707     0/imm32/no-imm8
33708     1/imm32/disp32-is-first-inout
33709     0/imm32/no-xm32
33710     0/imm32/no-x32
33711     0x11/imm32/alloc-id:fake
33712     _Primitive-break-if->-named/imm32/next
33713 _Primitive-break-if->-named:  # (payload primitive)
33714     0x11/imm32/alloc-id:fake:payload
33715     0x11/imm32/alloc-id:fake
33716     _string-break-if->/imm32/name
33717     0x11/imm32/alloc-id:fake
33718     Single-lit-var/imm32/inouts
33719     0/imm32/no-outputs
33720     0/imm32/no-outputs
33721     0x11/imm32/alloc-id:fake
33722     _string_0f_8f_jump_label/imm32/subx-name
33723     0/imm32/no-rm32
33724     0/imm32/no-r32
33725     0/imm32/no-imm32
33726     0/imm32/no-imm8
33727     1/imm32/disp32-is-first-inout
33728     0/imm32/no-xm32
33729     0/imm32/no-x32
33730     0x11/imm32/alloc-id:fake
33731     _Primitive-break-named/imm32/next
33732 _Primitive-break-named:  # (payload primitive)
33733     0x11/imm32/alloc-id:fake:payload
33734     0x11/imm32/alloc-id:fake
33735     _string-break/imm32/name
33736     0x11/imm32/alloc-id:fake
33737     Single-lit-var/imm32/inouts
33738     0/imm32/no-outputs
33739     0/imm32/no-outputs
33740     0x11/imm32/alloc-id:fake
33741     _string_e9_jump_label/imm32/subx-name
33742     0/imm32/no-rm32
33743     0/imm32/no-r32
33744     0/imm32/no-imm32
33745     0/imm32/no-imm8
33746     1/imm32/disp32-is-first-inout
33747     0/imm32/no-xm32
33748     0/imm32/no-x32
33749     0x11/imm32/alloc-id:fake
33750     _Primitive-loop-if-addr<-named/imm32/next
33751 _Primitive-loop-if-addr<-named:  # (payload primitive)
33752     0x11/imm32/alloc-id:fake:payload
33753     0x11/imm32/alloc-id:fake
33754     _string-loop-if-addr</imm32/name
33755     0x11/imm32/alloc-id:fake
33756     Single-lit-var/imm32/inouts
33757     0/imm32/no-outputs
33758     0/imm32/no-outputs
33759     0x11/imm32/alloc-id:fake
33760     _string_0f_82_jump_label/imm32/subx-name
33761     0/imm32/no-rm32
33762     0/imm32/no-r32
33763     0/imm32/no-imm32
33764     0/imm32/no-imm8
33765     1/imm32/disp32-is-first-inout
33766     0/imm32/no-xm32
33767     0/imm32/no-x32
33768     0x11/imm32/alloc-id:fake
33769     _Primitive-loop-if-addr>=-named/imm32/next
33770 _Primitive-loop-if-addr>=-named:  # (payload primitive)
33771     0x11/imm32/alloc-id:fake:payload
33772     0x11/imm32/alloc-id:fake
33773     _string-loop-if-addr>=/imm32/name
33774     0x11/imm32/alloc-id:fake
33775     Single-lit-var/imm32/inouts
33776     0/imm32/no-outputs
33777     0/imm32/no-outputs
33778     0x11/imm32/alloc-id:fake
33779     _string_0f_83_jump_label/imm32/subx-name
33780     0/imm32/no-rm32
33781     0/imm32/no-r32
33782     0/imm32/no-imm32
33783     0/imm32/no-imm8
33784     1/imm32/disp32-is-first-inout
33785     0/imm32/no-xm32
33786     0/imm32/no-x32
33787     0x11/imm32/alloc-id:fake
33788     _Primitive-loop-if-=-named/imm32/next
33789 _Primitive-loop-if-=-named:  # (payload primitive)
33790     0x11/imm32/alloc-id:fake:payload
33791     0x11/imm32/alloc-id:fake
33792     _string-loop-if-=/imm32/name
33793     0x11/imm32/alloc-id:fake
33794     Single-lit-var/imm32/inouts
33795     0/imm32/no-outputs
33796     0/imm32/no-outputs
33797     0x11/imm32/alloc-id:fake
33798     _string_0f_84_jump_label/imm32/subx-name
33799     0/imm32/no-rm32
33800     0/imm32/no-r32
33801     0/imm32/no-imm32
33802     0/imm32/no-imm8
33803     1/imm32/disp32-is-first-inout
33804     0/imm32/no-xm32
33805     0/imm32/no-x32
33806     0x11/imm32/alloc-id:fake
33807     _Primitive-loop-if-!=-named/imm32/next
33808 _Primitive-loop-if-!=-named:  # (payload primitive)
33809     0x11/imm32/alloc-id:fake:payload
33810     0x11/imm32/alloc-id:fake
33811     _string-loop-if-!=/imm32/name
33812     0x11/imm32/alloc-id:fake
33813     Single-lit-var/imm32/inouts
33814     0/imm32/no-outputs
33815     0/imm32/no-outputs
33816     0x11/imm32/alloc-id:fake
33817     _string_0f_85_jump_label/imm32/subx-name
33818     0/imm32/no-rm32
33819     0/imm32/no-r32
33820     0/imm32/no-imm32
33821     0/imm32/no-imm8
33822     1/imm32/disp32-is-first-inout
33823     0/imm32/no-xm32
33824     0/imm32/no-x32
33825     0x11/imm32/alloc-id:fake
33826     _Primitive-loop-if-addr<=-named/imm32/next
33827 _Primitive-loop-if-addr<=-named:  # (payload primitive)
33828     0x11/imm32/alloc-id:fake:payload
33829     0x11/imm32/alloc-id:fake
33830     _string-loop-if-addr<=/imm32/name
33831     0x11/imm32/alloc-id:fake
33832     Single-lit-var/imm32/inouts
33833     0/imm32/no-outputs
33834     0/imm32/no-outputs
33835     0x11/imm32/alloc-id:fake
33836     _string_0f_86_jump_label/imm32/subx-name
33837     0/imm32/no-rm32
33838     0/imm32/no-r32
33839     0/imm32/no-imm32
33840     0/imm32/no-imm8
33841     1/imm32/disp32-is-first-inout
33842     0/imm32/no-xm32
33843     0/imm32/no-x32
33844     0x11/imm32/alloc-id:fake
33845     _Primitive-loop-if-addr>-named/imm32/next
33846 _Primitive-loop-if-addr>-named:  # (payload primitive)
33847     0x11/imm32/alloc-id:fake:payload
33848     0x11/imm32/alloc-id:fake
33849     _string-loop-if-addr>/imm32/name
33850     0x11/imm32/alloc-id:fake
33851     Single-lit-var/imm32/inouts
33852     0/imm32/no-outputs
33853     0/imm32/no-outputs
33854     0x11/imm32/alloc-id:fake
33855     _string_0f_87_jump_label/imm32/subx-name
33856     0/imm32/no-rm32
33857     0/imm32/no-r32
33858     0/imm32/no-imm32
33859     0/imm32/no-imm8
33860     1/imm32/disp32-is-first-inout
33861     0/imm32/no-xm32
33862     0/imm32/no-x32
33863     0x11/imm32/alloc-id:fake
33864     _Primitive-loop-if-<-named/imm32/next
33865 _Primitive-loop-if-<-named:  # (payload primitive)
33866     0x11/imm32/alloc-id:fake:payload
33867     0x11/imm32/alloc-id:fake
33868     _string-loop-if-</imm32/name
33869     0x11/imm32/alloc-id:fake
33870     Single-lit-var/imm32/inouts
33871     0/imm32/no-outputs
33872     0/imm32/no-outputs
33873     0x11/imm32/alloc-id:fake
33874     _string_0f_8c_jump_label/imm32/subx-name
33875     0/imm32/no-rm32
33876     0/imm32/no-r32
33877     0/imm32/no-imm32
33878     0/imm32/no-imm8
33879     1/imm32/disp32-is-first-inout
33880     0/imm32/no-xm32
33881     0/imm32/no-x32
33882     0x11/imm32/alloc-id:fake
33883     _Primitive-loop-if->=-named/imm32/next
33884 _Primitive-loop-if->=-named:  # (payload primitive)
33885     0x11/imm32/alloc-id:fake:payload
33886     0x11/imm32/alloc-id:fake
33887     _string-loop-if->=/imm32/name
33888     0x11/imm32/alloc-id:fake
33889     Single-lit-var/imm32/inouts
33890     0/imm32/no-outputs
33891     0/imm32/no-outputs
33892     0x11/imm32/alloc-id:fake
33893     _string_0f_8d_jump_label/imm32/subx-name
33894     0/imm32/no-rm32
33895     0/imm32/no-r32
33896     0/imm32/no-imm32
33897     0/imm32/no-imm8
33898     1/imm32/disp32-is-first-inout
33899     0/imm32/no-xm32
33900     0/imm32/no-x32
33901     0x11/imm32/alloc-id:fake
33902     _Primitive-loop-if-<=-named/imm32/next
33903 _Primitive-loop-if-<=-named:  # (payload primitive)
33904     0x11/imm32/alloc-id:fake:payload
33905     0x11/imm32/alloc-id:fake
33906     _string-loop-if-<=/imm32/name
33907     0x11/imm32/alloc-id:fake
33908     Single-lit-var/imm32/inouts
33909     0/imm32/no-outputs
33910     0/imm32/no-outputs
33911     0x11/imm32/alloc-id:fake
33912     _string_0f_8e_jump_label/imm32/subx-name
33913     0/imm32/no-rm32
33914     0/imm32/no-r32
33915     0/imm32/no-imm32
33916     0/imm32/no-imm8
33917     1/imm32/disp32-is-first-inout
33918     0/imm32/no-xm32
33919     0/imm32/no-x32
33920     0x11/imm32/alloc-id:fake
33921     _Primitive-loop-if->-named/imm32/next
33922 _Primitive-loop-if->-named:  # (payload primitive)
33923     0x11/imm32/alloc-id:fake:payload
33924     0x11/imm32/alloc-id:fake
33925     _string-loop-if->/imm32/name
33926     0x11/imm32/alloc-id:fake
33927     Single-lit-var/imm32/inouts
33928     0/imm32/no-outputs
33929     0/imm32/no-outputs
33930     0x11/imm32/alloc-id:fake
33931     _string_0f_8f_jump_label/imm32/subx-name
33932     0/imm32/no-rm32
33933     0/imm32/no-r32
33934     0/imm32/no-imm32
33935     0/imm32/no-imm8
33936     1/imm32/disp32-is-first-inout
33937     0/imm32/no-xm32
33938     0/imm32/no-x32
33939     0x11/imm32/alloc-id:fake
33940     _Primitive-loop-named/imm32/next  # we probably don't need an unconditional break
33941 _Primitive-loop-named:  # (payload primitive)
33942     0x11/imm32/alloc-id:fake:payload
33943     0x11/imm32/alloc-id:fake
33944     _string-loop/imm32/name
33945     0x11/imm32/alloc-id:fake
33946     Single-lit-var/imm32/inouts
33947     0/imm32/no-outputs
33948     0/imm32/no-outputs
33949     0x11/imm32/alloc-id:fake
33950     _string_e9_jump_label/imm32/subx-name
33951     0/imm32/no-rm32
33952     0/imm32/no-r32
33953     0/imm32/no-imm32
33954     0/imm32/no-imm8
33955     1/imm32/disp32-is-first-inout
33956     0/imm32/no-xm32
33957     0/imm32/no-x32
33958     0x11/imm32/alloc-id:fake
33959     _Primitive-break-if-float</imm32/next
33960 # - branches based on floating-point comparisons
33961 _Primitive-break-if-float<:  # (payload primitive)
33962     0x11/imm32/alloc-id:fake:payload
33963     0x11/imm32/alloc-id:fake
33964     _string-break-if-float</imm32/name
33965     0/imm32/no-inouts
33966     0/imm32/no-inouts
33967     0/imm32/no-outputs
33968     0/imm32/no-outputs
33969     0x11/imm32/alloc-id:fake
33970     _string_0f_82_jump_break/imm32/subx-name
33971     0/imm32/no-rm32
33972     0/imm32/no-r32
33973     0/imm32/no-imm32
33974     0/imm32/no-imm8
33975     0/imm32/no-disp32
33976     0/imm32/no-xm32
33977     0/imm32/no-x32
33978     0x11/imm32/alloc-id:fake
33979     _Primitive-break-if-float>=/imm32/next
33980 _Primitive-break-if-float>=:  # (payload primitive)
33981     0x11/imm32/alloc-id:fake:payload
33982     0x11/imm32/alloc-id:fake
33983     _string-break-if-float>=/imm32/name
33984     0/imm32/no-inouts
33985     0/imm32/no-inouts
33986     0/imm32/no-outputs
33987     0/imm32/no-outputs
33988     0x11/imm32/alloc-id:fake
33989     _string_0f_83_jump_break/imm32/subx-name
33990     0/imm32/no-rm32
33991     0/imm32/no-r32
33992     0/imm32/no-imm32
33993     0/imm32/no-imm8
33994     0/imm32/no-disp32
33995     0/imm32/no-xm32
33996     0/imm32/no-x32
33997     0x11/imm32/alloc-id:fake
33998     _Primitive-break-if-float<=/imm32/next
33999 _Primitive-break-if-float<=:  # (payload primitive)
34000     0x11/imm32/alloc-id:fake:payload
34001     0x11/imm32/alloc-id:fake
34002     _string-break-if-float<=/imm32/name
34003     0/imm32/no-inouts
34004     0/imm32/no-inouts
34005     0/imm32/no-outputs
34006     0/imm32/no-outputs
34007     0x11/imm32/alloc-id:fake
34008     _string_0f_86_jump_break/imm32/subx-name
34009     0/imm32/no-rm32
34010     0/imm32/no-r32
34011     0/imm32/no-imm32
34012     0/imm32/no-imm8
34013     0/imm32/no-disp32
34014     0/imm32/no-xm32
34015     0/imm32/no-x32
34016     0x11/imm32/alloc-id:fake
34017     _Primitive-break-if-float>/imm32/next
34018 _Primitive-break-if-float>:  # (payload primitive)
34019     0x11/imm32/alloc-id:fake:payload
34020     0x11/imm32/alloc-id:fake
34021     _string-break-if-float>/imm32/name
34022     0/imm32/no-inouts
34023     0/imm32/no-inouts
34024     0/imm32/no-outputs
34025     0/imm32/no-outputs
34026     0x11/imm32/alloc-id:fake
34027     _string_0f_87_jump_break/imm32/subx-name
34028     0/imm32/no-rm32
34029     0/imm32/no-r32
34030     0/imm32/no-imm32
34031     0/imm32/no-imm8
34032     0/imm32/no-disp32
34033     0/imm32/no-xm32
34034     0/imm32/no-x32
34035     0x11/imm32/alloc-id:fake
34036     _Primitive-loop-if-float</imm32/next
34037 _Primitive-loop-if-float<:  # (payload primitive)
34038     0x11/imm32/alloc-id:fake:payload
34039     0x11/imm32/alloc-id:fake
34040     _string-loop-if-float</imm32/name
34041     0/imm32/no-inouts
34042     0/imm32/no-inouts
34043     0/imm32/no-outputs
34044     0/imm32/no-outputs
34045     0x11/imm32/alloc-id:fake
34046     _string_0f_82_jump_loop/imm32/subx-name
34047     0/imm32/no-rm32
34048     0/imm32/no-r32
34049     0/imm32/no-imm32
34050     0/imm32/no-imm8
34051     0/imm32/no-disp32
34052     0/imm32/no-xm32
34053     0/imm32/no-x32
34054     0x11/imm32/alloc-id:fake
34055     _Primitive-loop-if-float>=/imm32/next
34056 _Primitive-loop-if-float>=:  # (payload primitive)
34057     0x11/imm32/alloc-id:fake:payload
34058     0x11/imm32/alloc-id:fake
34059     _string-loop-if-float>=/imm32/name
34060     0/imm32/no-inouts
34061     0/imm32/no-inouts
34062     0/imm32/no-outputs
34063     0/imm32/no-outputs
34064     0x11/imm32/alloc-id:fake
34065     _string_0f_83_jump_loop/imm32/subx-name
34066     0/imm32/no-rm32
34067     0/imm32/no-r32
34068     0/imm32/no-imm32
34069     0/imm32/no-imm8
34070     0/imm32/no-disp32
34071     0/imm32/no-xm32
34072     0/imm32/no-x32
34073     0x11/imm32/alloc-id:fake
34074     _Primitive-loop-if-float<=/imm32/next
34075 _Primitive-loop-if-float<=:  # (payload primitive)
34076     0x11/imm32/alloc-id:fake:payload
34077     0x11/imm32/alloc-id:fake
34078     _string-loop-if-float<=/imm32/name
34079     0/imm32/no-inouts
34080     0/imm32/no-inouts
34081     0/imm32/no-outputs
34082     0/imm32/no-outputs
34083     0x11/imm32/alloc-id:fake
34084     _string_0f_86_jump_loop/imm32/subx-name
34085     0/imm32/no-rm32
34086     0/imm32/no-r32
34087     0/imm32/no-imm32
34088     0/imm32/no-imm8
34089     0/imm32/no-disp32
34090     0/imm32/no-xm32
34091     0/imm32/no-x32
34092     0x11/imm32/alloc-id:fake
34093     _Primitive-loop-if-float>/imm32/next
34094 _Primitive-loop-if-float>:  # (payload primitive)
34095     0x11/imm32/alloc-id:fake:payload
34096     0x11/imm32/alloc-id:fake
34097     _string-loop-if-float>/imm32/name
34098     0/imm32/no-inouts
34099     0/imm32/no-inouts
34100     0/imm32/no-outputs
34101     0/imm32/no-outputs
34102     0x11/imm32/alloc-id:fake
34103     _string_0f_87_jump_loop/imm32/subx-name
34104     0/imm32/no-rm32
34105     0/imm32/no-r32
34106     0/imm32/no-imm32
34107     0/imm32/no-imm8
34108     0/imm32/no-disp32
34109     0/imm32/no-xm32
34110     0/imm32/no-x32
34111     0x11/imm32/alloc-id:fake
34112     _Primitive-break-if-float<-named/imm32/next
34113 _Primitive-break-if-float<-named:  # (payload primitive)
34114     0x11/imm32/alloc-id:fake:payload
34115     0x11/imm32/alloc-id:fake
34116     _string-break-if-float</imm32/name
34117     0x11/imm32/alloc-id:fake
34118     Single-lit-var/imm32/inouts
34119     0/imm32/no-outputs
34120     0/imm32/no-outputs
34121     0x11/imm32/alloc-id:fake
34122     _string_0f_82_jump_label/imm32/subx-name
34123     0/imm32/no-rm32
34124     0/imm32/no-r32
34125     0/imm32/no-imm32
34126     0/imm32/no-imm8
34127     1/imm32/disp32-is-first-inout
34128     0/imm32/no-xm32
34129     0/imm32/no-x32
34130     0x11/imm32/alloc-id:fake
34131     _Primitive-break-if-float>=-named/imm32/next
34132 _Primitive-break-if-float>=-named:  # (payload primitive)
34133     0x11/imm32/alloc-id:fake:payload
34134     0x11/imm32/alloc-id:fake
34135     _string-break-if-float>=/imm32/name
34136     0x11/imm32/alloc-id:fake
34137     Single-lit-var/imm32/inouts
34138     0/imm32/no-outputs
34139     0/imm32/no-outputs
34140     0x11/imm32/alloc-id:fake
34141     _string_0f_83_jump_label/imm32/subx-name
34142     0/imm32/no-rm32
34143     0/imm32/no-r32
34144     0/imm32/no-imm32
34145     0/imm32/no-imm8
34146     1/imm32/disp32-is-first-inout
34147     0/imm32/no-xm32
34148     0/imm32/no-x32
34149     0x11/imm32/alloc-id:fake
34150     _Primitive-break-if-float<=-named/imm32/next
34151 _Primitive-break-if-float<=-named:  # (payload primitive)
34152     0x11/imm32/alloc-id:fake:payload
34153     0x11/imm32/alloc-id:fake
34154     _string-break-if-float<=/imm32/name
34155     0x11/imm32/alloc-id:fake
34156     Single-lit-var/imm32/inouts
34157     0/imm32/no-outputs
34158     0/imm32/no-outputs
34159     0x11/imm32/alloc-id:fake
34160     _string_0f_86_jump_label/imm32/subx-name
34161     0/imm32/no-rm32
34162     0/imm32/no-r32
34163     0/imm32/no-imm32
34164     0/imm32/no-imm8
34165     1/imm32/disp32-is-first-inout
34166     0/imm32/no-xm32
34167     0/imm32/no-x32
34168     0x11/imm32/alloc-id:fake
34169     _Primitive-break-if-float>-named/imm32/next
34170 _Primitive-break-if-float>-named:  # (payload primitive)
34171     0x11/imm32/alloc-id:fake:payload
34172     0x11/imm32/alloc-id:fake
34173     _string-break-if-float>/imm32/name
34174     0x11/imm32/alloc-id:fake
34175     Single-lit-var/imm32/inouts
34176     0/imm32/no-outputs
34177     0/imm32/no-outputs
34178     0x11/imm32/alloc-id:fake
34179     _string_0f_87_jump_label/imm32/subx-name
34180     0/imm32/no-rm32
34181     0/imm32/no-r32
34182     0/imm32/no-imm32
34183     0/imm32/no-imm8
34184     1/imm32/disp32-is-first-inout
34185     0/imm32/no-xm32
34186     0/imm32/no-x32
34187     0x11/imm32/alloc-id:fake
34188     _Primitive-loop-if-float<-named/imm32/next
34189 _Primitive-loop-if-float<-named:  # (payload primitive)
34190     0x11/imm32/alloc-id:fake:payload
34191     0x11/imm32/alloc-id:fake
34192     _string-loop-if-float</imm32/name
34193     0x11/imm32/alloc-id:fake
34194     Single-lit-var/imm32/inouts
34195     0/imm32/no-outputs
34196     0/imm32/no-outputs
34197     0x11/imm32/alloc-id:fake
34198     _string_0f_82_jump_label/imm32/subx-name
34199     0/imm32/no-rm32
34200     0/imm32/no-r32
34201     0/imm32/no-imm32
34202     0/imm32/no-imm8
34203     1/imm32/disp32-is-first-inout
34204     0/imm32/no-xm32
34205     0/imm32/no-x32
34206     0x11/imm32/alloc-id:fake
34207     _Primitive-loop-if-float>=-named/imm32/next
34208 _Primitive-loop-if-float>=-named:  # (payload primitive)
34209     0x11/imm32/alloc-id:fake:payload
34210     0x11/imm32/alloc-id:fake
34211     _string-loop-if-float>=/imm32/name
34212     0x11/imm32/alloc-id:fake
34213     Single-lit-var/imm32/inouts
34214     0/imm32/no-outputs
34215     0/imm32/no-outputs
34216     0x11/imm32/alloc-id:fake
34217     _string_0f_83_jump_label/imm32/subx-name
34218     0/imm32/no-rm32
34219     0/imm32/no-r32
34220     0/imm32/no-imm32
34221     0/imm32/no-imm8
34222     1/imm32/disp32-is-first-inout
34223     0/imm32/no-xm32
34224     0/imm32/no-x32
34225     0x11/imm32/alloc-id:fake
34226     _Primitive-loop-if-float<=-named/imm32/next
34227 _Primitive-loop-if-float<=-named:  # (payload primitive)
34228     0x11/imm32/alloc-id:fake:payload
34229     0x11/imm32/alloc-id:fake
34230     _string-loop-if-float<=/imm32/name
34231     0x11/imm32/alloc-id:fake
34232     Single-lit-var/imm32/inouts
34233     0/imm32/no-outputs
34234     0/imm32/no-outputs
34235     0x11/imm32/alloc-id:fake
34236     _string_0f_86_jump_label/imm32/subx-name
34237     0/imm32/no-rm32
34238     0/imm32/no-r32
34239     0/imm32/no-imm32
34240     0/imm32/no-imm8
34241     1/imm32/disp32-is-first-inout
34242     0/imm32/no-xm32
34243     0/imm32/no-x32
34244     0x11/imm32/alloc-id:fake
34245     _Primitive-loop-if-float>-named/imm32/next
34246 _Primitive-loop-if-float>-named:  # (payload primitive)
34247     0x11/imm32/alloc-id:fake:payload
34248     0x11/imm32/alloc-id:fake
34249     _string-loop-if-float>/imm32/name
34250     0x11/imm32/alloc-id:fake
34251     Single-lit-var/imm32/inouts
34252     0/imm32/no-outputs
34253     0/imm32/no-outputs
34254     0x11/imm32/alloc-id:fake
34255     _string_0f_87_jump_label/imm32/subx-name
34256     0/imm32/no-rm32
34257     0/imm32/no-r32
34258     0/imm32/no-imm32
34259     0/imm32/no-imm8
34260     1/imm32/disp32-is-first-inout
34261     0/imm32/no-xm32
34262     0/imm32/no-x32
34263     0/imm32/next
34264     0/imm32/next
34266 # string literals for Mu instructions
34267 _string-add:  # (payload array byte)
34268     0x11/imm32/alloc-id:fake:payload
34269     # "add"
34270     0x3/imm32/size
34271     0x61/a 0x64/d 0x64/d
34272 _string-address:  # (payload array byte)
34273     0x11/imm32/alloc-id:fake:payload
34274     # "address"
34275     0x7/imm32/size
34276     0x61/a 0x64/d 0x64/d 0x72/r 0x65/e 0x73/s 0x73/s
34277 _string-add-to:  # (payload array byte)
34278     0x11/imm32/alloc-id:fake:payload
34279     # "add-to"
34280     0x6/imm32/size
34281     0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
34282 _string-and:  # (payload array byte)
34283     0x11/imm32/alloc-id:fake:payload
34284     # "and"
34285     0x3/imm32/size
34286     0x61/a 0x6e/n 0x64/d
34287 _string-and-with:  # (payload array byte)
34288     0x11/imm32/alloc-id:fake:payload
34289     # "and-with"
34290     0x8/imm32/size
34291     0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
34292 _string-break:  # (payload array byte)
34293     0x11/imm32/alloc-id:fake:payload
34294     # "break"
34295     0x5/imm32/size
34296     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k
34297 _string-break-if-<:  # (payload array byte)
34298     0x11/imm32/alloc-id:fake:payload
34299     # "break-if-<"
34300     0xa/imm32/size
34301     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
34302 _string-break-if-<=:  # (payload array byte)
34303     0x11/imm32/alloc-id:fake:payload
34304     # "break-if-<="
34305     0xb/imm32/size
34306     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
34307 _string-break-if-=:  # (payload array byte)
34308     0x11/imm32/alloc-id:fake:payload
34309     # "break-if-="
34310     0xa/imm32/size
34311     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
34312 _string-break-if->:  # (payload array byte)
34313     0x11/imm32/alloc-id:fake:payload
34314     # "break-if->"
34315     0xa/imm32/size
34316     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
34317 _string-break-if->=:  # (payload array byte)
34318     0x11/imm32/alloc-id:fake:payload
34319     # "break-if->="
34320     0xb/imm32/size
34321     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
34322 _string-break-if-!=:  # (payload array byte)
34323     0x11/imm32/alloc-id:fake:payload
34324     # "break-if-!="
34325     0xb/imm32/size
34326     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
34327 _string-break-if-addr<:  # (payload array byte)
34328     0x11/imm32/alloc-id:fake:payload
34329     # "break-if-addr<"
34330     0xe/imm32/size
34331     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/<
34332 _string-break-if-addr<=:  # (payload array byte)
34333     0x11/imm32/alloc-id:fake:payload
34334     # "break-if-addr<="
34335     0xf/imm32/size
34336     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/=
34337 _string-break-if-addr>:  # (payload array byte)
34338     0x11/imm32/alloc-id:fake:payload
34339     # "break-if-addr>"
34340     0xe/imm32/size
34341     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/>
34342 _string-break-if-addr>=:  # (payload array byte)
34343     0x11/imm32/alloc-id:fake:payload
34344     # "break-if-addr>="
34345     0xf/imm32/size
34346     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/=
34347 _string-break-if-float<:  # (payload array byte)
34348     0x11/imm32/alloc-id:fake:payload
34349     # "break-if-float<"
34350     0xf/imm32/size
34351     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x66/f 0x6c/l 0x6f/o 0x61/a 0x74/t 0x3c/<
34352 _string-break-if-float<=:  # (payload array byte)
34353     0x11/imm32/alloc-id:fake:payload
34354     # "break-if-float<="
34355     0x10/imm32/size
34356     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x66/f 0x6c/l 0x6f/o 0x61/a 0x74/t 0x3c/< 0x3d/=
34357 _string-break-if-float>:  # (payload array byte)
34358     0x11/imm32/alloc-id:fake:payload
34359     # "break-if-float>"
34360     0xf/imm32/size
34361     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x66/f 0x6c/l 0x6f/o 0x61/a 0x74/t 0x3e/>
34362 _string-break-if-float>=:  # (payload array byte)
34363     0x11/imm32/alloc-id:fake:payload
34364     # "break-if-float>="
34365     0x10/imm32/size
34366     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x66/f 0x6c/l 0x6f/o 0x61/a 0x74/t 0x3e/> 0x3d/=
34367 _string-break-if-carry:  # (payload array byte)
34368     0x11/imm32/alloc-id:fake:payload
34369     # "break-if-carry"
34370     0xe/imm32/size
34371     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x63/c 0x61/a 0x72/r 0x72/r 0x79/y
34372 _string-break-if-not-carry:  # (payload array byte)
34373     0x11/imm32/alloc-id:fake:payload
34374     # "break-if-not-carry"
34375     0x12/imm32/size
34376     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x6e/n 0x6f/o 0x74/t 0x2d/dash 0x63/c 0x61/a 0x72/r 0x72/r 0x79/y
34377 _string-break-if-overflow:  # (payload array byte)
34378     0x11/imm32/alloc-id:fake:payload
34379     # "break-if-overflow"
34380     0x11/imm32/size
34381     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x6f/o 0x76/v 0x65/e 0x72/r 0x66/f 0x6c/l 0x6f/o 0x77/w
34382 _string-break-if-not-overflow:  # (payload array byte)
34383     0x11/imm32/alloc-id:fake:payload
34384     # "break-if-not-overflow"
34385     0x15/imm32/size
34386     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x6e/n 0x6f/o 0x74/t 0x2d/dash 0x6f/o 0x76/v 0x65/e 0x72/r 0x66/f 0x6c/l 0x6f/o 0x77/w
34387 _string-compare:  # (payload array byte)
34388     0x11/imm32/alloc-id:fake:payload
34389     # "compare"
34390     0x7/imm32/size
34391     0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e
34392 _string-copy:  # (payload array byte)
34393     0x11/imm32/alloc-id:fake:payload
34394     # "copy"
34395     0x4/imm32/size
34396     0x63/c 0x6f/o 0x70/p 0x79/y
34397 _string-copy-to:  # (payload array byte)
34398     0x11/imm32/alloc-id:fake:payload
34399     # "copy-to"
34400     0x7/imm32/size
34401     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o
34402 _string-copy-byte:
34403     0x11/imm32/alloc-id:fake:payload
34404     # "copy-byte"
34405     0x9/imm32/size
34406     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x62/b 0x79/y 0x74/t 0x65/e
34407 _string-copy-byte-to:
34408     0x11/imm32/alloc-id:fake:payload
34409     # "copy-byte-to"
34410     0xc/imm32/size
34411     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/dash 0x74/t 0x6f/o
34412 _string-decrement:  # (payload array byte)
34413     0x11/imm32/alloc-id:fake:payload
34414     # "decrement"
34415     0x9/imm32/size
34416     0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
34417 _string-increment:  # (payload array byte)
34418     0x11/imm32/alloc-id:fake:payload
34419     # "increment"
34420     0x9/imm32/size
34421     0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
34422 _string-loop:  # (payload array byte)
34423     0x11/imm32/alloc-id:fake:payload
34424     # "loop"
34425     0x4/imm32/size
34426     0x6c/l 0x6f/o 0x6f/o 0x70/p
34427 _string-loop-if-<:  # (payload array byte)
34428     0x11/imm32/alloc-id:fake:payload
34429     # "loop-if-<"
34430     0x9/imm32/size
34431     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
34432 _string-loop-if-<=:  # (payload array byte)
34433     0x11/imm32/alloc-id:fake:payload
34434     # "loop-if-<="
34435     0xa/imm32/size
34436     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
34437 _string-loop-if-=:  # (payload array byte)
34438     0x11/imm32/alloc-id:fake:payload
34439     # "loop-if-="
34440     0x9/imm32/size
34441     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
34442 _string-loop-if->:  # (payload array byte)
34443     0x11/imm32/alloc-id:fake:payload
34444     # "loop-if->"
34445     0x9/imm32/size
34446     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
34447 _string-loop-if->=:  # (payload array byte)
34448     0x11/imm32/alloc-id:fake:payload
34449     # "loop-if->="
34450     0xa/imm32/size
34451     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
34452 _string-loop-if-!=:  # (payload array byte)
34453     0x11/imm32/alloc-id:fake:payload
34454     # "loop-if-!="
34455     0xa/imm32/size
34456     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
34457 _string-loop-if-addr<:  # (payload array byte)
34458     0x11/imm32/alloc-id:fake:payload
34459     # "loop-if-addr<"
34460     0xd/imm32/size
34461     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/<
34462 _string-loop-if-addr<=:  # (payload array byte)
34463     0x11/imm32/alloc-id:fake:payload
34464     # "loop-if-addr<="
34465     0xe/imm32/size
34466     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/=
34467 _string-loop-if-addr>:  # (payload array byte)
34468     0x11/imm32/alloc-id:fake:payload
34469     # "loop-if-addr>"
34470     0xd/imm32/size
34471     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/>
34472 _string-loop-if-addr>=:  # (payload array byte)
34473     0x11/imm32/alloc-id:fake:payload
34474     # "loop-if-addr>="
34475     0xe/imm32/size
34476     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/=
34477 _string-loop-if-float<:  # (payload array byte)
34478     0x11/imm32/alloc-id:fake:payload
34479     # "loop-if-float<"
34480     0xe/imm32/size
34481     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x66/f 0x6c/l 0x6f/o 0x61/a 0x74/t 0x3c/<
34482 _string-loop-if-float<=:  # (payload array byte)
34483     0x11/imm32/alloc-id:fake:payload
34484     # "loop-if-float<="
34485     0xf/imm32/size
34486     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x66/f 0x6c/l 0x6f/o 0x61/a 0x74/t 0x3c/< 0x3d/=
34487 _string-loop-if-float>:  # (payload array byte)
34488     0x11/imm32/alloc-id:fake:payload
34489     # "loop-if-float>"
34490     0xe/imm32/size
34491     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x66/f 0x6c/l 0x6f/o 0x61/a 0x74/t 0x3e/>
34492 _string-loop-if-float>=:  # (payload array byte)
34493     0x11/imm32/alloc-id:fake:payload
34494     # "loop-if-float>="
34495     0xf/imm32/size
34496     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x66/f 0x6c/l 0x6f/o 0x61/a 0x74/t 0x3e/> 0x3d/=
34497 _string-loop-if-carry:  # (payload array byte)
34498     0x11/imm32/alloc-id:fake:payload
34499     # "loop-if-carry"
34500     0xd/imm32/size
34501     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x63/c 0x61/a 0x72/r 0x72/r 0x79/y
34502 _string-loop-if-not-carry:  # (payload array byte)
34503     0x11/imm32/alloc-id:fake:payload
34504     # "loop-if-not-carry"
34505     0x11/imm32/size
34506     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x6e/n 0x6f/o 0x74/t 0x2d/dash 0x63/c 0x61/a 0x72/r 0x72/r 0x79/y
34507 _string-loop-if-overflow:  # (payload array byte)
34508     0x11/imm32/alloc-id:fake:payload
34509     # "loop-if-overflow"
34510     0x10/imm32/size
34511     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x6f/o 0x76/v 0x65/e 0x72/r 0x66/f 0x6c/l 0x6f/o 0x77/w
34512 _string-loop-if-not-overflow:  # (payload array byte)
34513     0x11/imm32/alloc-id:fake:payload
34514     # "loop-if-not-overflow"
34515     0x14/imm32/size
34516     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x6e/n 0x6f/o 0x74/t 0x2d/dash 0x6f/o 0x76/v 0x65/e 0x72/r 0x66/f 0x6c/l 0x6f/o 0x77/w
34517 _string-multiply:  # (payload array byte)
34518     0x11/imm32/alloc-id:fake:payload
34519     # "multiply"
34520     0x8/imm32/size
34521     0x6d/m 0x75/u 0x6c/l 0x74/t 0x69/i 0x70/p 0x6c/l 0x79/y
34522 _string-convert:  # (payload array byte)
34523     0x11/imm32/alloc-id:fake:payload
34524     # "convert"
34525     0x7/imm32/size
34526     0x63/c 0x6f/o 0x6e/n 0x76/v 0x65/e 0x72/r 0x74/t
34527 _string-truncate:  # (payload array byte)
34528     0x11/imm32/alloc-id:fake:payload
34529     # "truncate"
34530     0x8/imm32/size
34531     0x74/t 0x72/r 0x75/u 0x6e/n 0x63/c 0x61/a 0x74/t 0x65/e
34532 _string-reinterpret:  # (payload array byte)
34533     0x11/imm32/alloc-id:fake:payload
34534     # "reinterpret"
34535     0xb/imm32/size
34536     0x72/r 0x65/e 0x69/i 0x6e/n 0x74/t 0x65/e 0x72/r 0x70/p 0x72/r 0x65/e 0x74/t
34537 _string-divide:
34538     0x11/imm32/alloc-id:fake:payload
34539     # "divide"
34540     0x6/imm32/size
34541     0x64/d 0x69/i 0x76/v 0x69/i 0x64/d 0x65/e
34542 _string-max:
34543     0x11/imm32/alloc-id:fake:payload
34544     # "max"
34545     0x3/imm32/size
34546     0x6d/m 0x61/a 0x78/x
34547 _string-min:
34548     0x11/imm32/alloc-id:fake:payload
34549     # "min"
34550     0x3/imm32/size
34551     0x6d/m 0x69/i 0x6e/n
34552 _string-reciprocal:
34553     0x11/imm32/alloc-id:fake:payload
34554     # "reciprocal"
34555     0xa/imm32/size
34556     0x72/r 0x65/e 0x63/c 0x69/i 0x70/p 0x72/r 0x6f/o 0x63/c 0x61/a 0x6c/l
34557 _string-square-root:
34558     0x11/imm32/alloc-id:fake:payload
34559     # "square-root"
34560     0xb/imm32/size
34561     0x73/s 0x71/q 0x75/u 0x61/a 0x72/r 0x65/e 0x2d/dash 0x72/r 0x6f/o 0x6f/o 0x74/t
34562 _string-inverse-square-root:
34563     0x11/imm32/alloc-id:fake:payload
34564     # "inverse-square-root"
34565     0x13/imm32/size
34566     0x69/i 0x6e/n 0x76/v 0x65/e 0x72/r 0x73/s 0x65/e 0x2d/dash 0x73/s 0x71/q 0x75/u 0x61/a 0x72/r 0x65/e 0x2d/dash 0x72/r 0x6f/o 0x6f/o 0x74/t
34567 _string-negate:  # (payload array byte)
34568     0x11/imm32/alloc-id:fake:payload
34569     # "negate"
34570     0x6/imm32/size
34571     0x6e/n 0x65/e 0x67/g 0x61/a 0x74/t 0x65/e
34572 _string-not:  # (payload array byte)
34573     0x11/imm32/alloc-id:fake:payload
34574     # "not"
34575     0x3/imm32/size
34576     0x6e/n 0x6f/o 0x74/t
34577 _string-or:  # (payload array byte)
34578     0x11/imm32/alloc-id:fake:payload
34579     # "or"
34580     0x2/imm32/size
34581     0x6f/o 0x72/r
34582 _string-or-with:  # (payload array byte)
34583     0x11/imm32/alloc-id:fake:payload
34584     # "or-with"
34585     0x7/imm32/size
34586     0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
34587 _string-subtract:  # (payload array byte)
34588     0x11/imm32/alloc-id:fake:payload
34589     # "subtract"
34590     0x8/imm32/size
34591     0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
34592 _string-subtract-from:  # (payload array byte)
34593     0x11/imm32/alloc-id:fake:payload
34594     # "subtract-from"
34595     0xd/imm32/size
34596     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
34597 _string-xor:  # (payload array byte)
34598     0x11/imm32/alloc-id:fake:payload
34599     # "xor"
34600     0x3/imm32/size
34601     0x78/x 0x6f/o 0x72/r
34602 _string-xor-with:  # (payload array byte)
34603     0x11/imm32/alloc-id:fake:payload
34604     # "xor-with"
34605     0x8/imm32/size
34606     0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
34607 _string-shift-left:  # (payload array byte)
34608     0x11/imm32/alloc-id:fake:payload
34609     # "shift-left"
34610     0xa/imm32/size
34611     0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x2d/dash 0x6c/l 0x65/e 0x66/f 0x74/t
34612 _string-shift-right:  # (payload array byte)
34613     0x11/imm32/alloc-id:fake:payload
34614     # "shift-right"
34615     0xb/imm32/size
34616     0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x2d/dash 0x72/r 0x69/i 0x67/g 0x68/h 0x74/t
34617 _string-shift-right-signed:  # (payload array byte)
34618     0x11/imm32/alloc-id:fake:payload
34619     # "shift-right-signed"
34620     0x12/imm32/size
34621     0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x2d/dash 0x72/r 0x69/i 0x67/g 0x68/h 0x74/t 0x2d/dash 0x73/s 0x69/i 0x67/g 0x6e/n 0x65/e 0x64/d
34623 # string literals for SubX instructions
34624 _string_01_add_to:  # (payload array byte)
34625     0x11/imm32/alloc-id:fake:payload
34626     # "01/add-to"
34627     0x9/imm32/size
34628     0x30/0 0x31/1 0x2f/slash 0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
34629 _string_03_add:  # (payload array byte)
34630     0x11/imm32/alloc-id:fake:payload
34631     # "03/add"
34632     0x6/imm32/size
34633     0x30/0 0x33/3 0x2f/slash 0x61/a 0x64/d 0x64/d
34634 _string_05_add_to_eax:  # (payload array byte)
34635     0x11/imm32/alloc-id:fake:payload
34636     # "05/add-to-eax"
34637     0xd/imm32/size
34638     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
34639 _string_09_or_with:  # (payload array byte)
34640     0x11/imm32/alloc-id:fake:payload
34641     # "09/or-with"
34642     0xa/imm32/size
34643     0x30/0 0x39/9 0x2f/slash 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
34644 _string_0b_or:  # (payload array byte)
34645     0x11/imm32/alloc-id:fake:payload
34646     # "0b/or"
34647     0x5/imm32/size
34648     0x30/0 0x62/b 0x2f/slash 0x6f/o 0x72/r
34649 _string_0d_or_with_eax:  # (payload array byte)
34650     0x11/imm32/alloc-id:fake:payload
34651     # "0d/or-with-eax"
34652     0xe/imm32/size
34653     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
34654 _string_0f_80_jump_label:  # (payload array byte)
34655     0x11/imm32/alloc-id:fake:payload
34656     # "0f 80/jump-if-overflow"
34657     0x16/imm32/size
34658     0x30/0 0x66/f 0x20/space 0x38/8 0x30/0 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x6f/o 0x76/v 0x65/e 0x72/r 0x66/f 0x6c/l 0x6f/o 0x77/w
34659 _string_0f_80_jump_break:  # (payload array byte)
34660     0x11/imm32/alloc-id:fake:payload
34661     # "0f 80/jump-if-overflow break/disp32"
34662     0x23/imm32/size
34663     0x30/0 0x66/f 0x20/space 0x38/8 0x30/0 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x6f/o 0x76/v 0x65/e 0x72/r 0x66/f 0x6c/l 0x6f/o 0x77/w 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
34664 _string_0f_80_jump_loop:  # (payload array byte)
34665     0x11/imm32/alloc-id:fake:payload
34666     # "0f 80/jump-if-overflow loop/disp32"
34667     0x22/imm32/size
34668     0x30/0 0x66/f 0x20/space 0x38/8 0x30/0 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x6f/o 0x76/v 0x65/e 0x72/r 0x66/f 0x6c/l 0x6f/o 0x77/w 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
34669 _string_0f_81_jump_label:  # (payload array byte)
34670     0x11/imm32/alloc-id:fake:payload
34671     # "0f 81/jump-if-not-overflow"
34672     0x1a/imm32/size
34673     0x30/0 0x66/f 0x20/space 0x38/8 0x31/1 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x6e/n 0x6f/o 0x74/t 0x2d/dash 0x6f/o 0x76/v 0x65/e 0x72/r 0x66/f 0x6c/l 0x6f/o 0x77/w
34674 _string_0f_81_jump_break:  # (payload array byte)
34675     0x11/imm32/alloc-id:fake:payload
34676     # "0f 81/jump-if-not-overflow break/disp32"
34677     0x27/imm32/size
34678     0x30/0 0x66/f 0x20/space 0x38/8 0x31/1 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x6e/n 0x6f/o 0x74/t 0x2d/dash 0x6f/o 0x76/v 0x65/e 0x72/r 0x66/f 0x6c/l 0x6f/o 0x77/w 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
34679 _string_0f_81_jump_loop:  # (payload array byte)
34680     0x11/imm32/alloc-id:fake:payload
34681     # "0f 81/jump-if-not-overflow loop/disp32"
34682     0x26/imm32/size
34683     0x30/0 0x66/f 0x20/space 0x38/8 0x31/1 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x6e/n 0x6f/o 0x74/t 0x2d/dash 0x6f/o 0x76/v 0x65/e 0x72/r 0x66/f 0x6c/l 0x6f/o 0x77/w 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
34684 _string_0f_82_jump_label:  # (payload array byte)
34685     0x11/imm32/alloc-id:fake:payload
34686     # "0f 82/jump-if-addr<"
34687     0x13/imm32/size
34688     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/<
34689 _string_0f_82_jump_break:  # (payload array byte)
34690     0x11/imm32/alloc-id:fake:payload
34691     # "0f 82/jump-if-addr< break/disp32"
34692     0x20/imm32/size
34693     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
34694 _string_0f_82_jump_loop:  # (payload array byte)
34695     0x11/imm32/alloc-id:fake:payload
34696     # "0f 82/jump-if-addr< loop/disp32"
34697     0x1f/imm32/size
34698     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
34699 _string_0f_83_jump_label:  # (payload array byte)
34700     0x11/imm32/alloc-id:fake:payload
34701     # "0f 83/jump-if-addr>="
34702     0x14/imm32/size
34703     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/=
34704 _string_0f_83_jump_break:  # (payload array byte)
34705     0x11/imm32/alloc-id:fake:payload
34706     # "0f 83/jump-if-addr>= break/disp32"
34707     0x21/imm32/size
34708     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
34709 _string_0f_83_jump_loop:  # (payload array byte)
34710     0x11/imm32/alloc-id:fake:payload
34711     # "0f 83/jump-if-addr>= loop/disp32"
34712     0x20/imm32/size
34713     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
34714 _string_0f_84_jump_label:  # (payload array byte)
34715     0x11/imm32/alloc-id:fake:payload
34716     # "0f 84/jump-if-="
34717     0xf/imm32/size
34718     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/=
34719 _string_0f_84_jump_break:  # (payload array byte)
34720     0x11/imm32/alloc-id:fake:payload
34721     # "0f 84/jump-if-= break/disp32"
34722     0x1c/imm32/size
34723     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
34724 _string_0f_84_jump_loop:  # (payload array byte)
34725     0x11/imm32/alloc-id:fake:payload
34726     # "0f 84/jump-if-= loop/disp32"
34727     0x1a/imm32/size
34728     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
34729 _string_0f_85_jump_label:  # (payload array byte)
34730     0x11/imm32/alloc-id:fake:payload
34731     # "0f 85/jump-if-!="
34732     0x10/imm32/size
34733     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/=
34734 _string_0f_85_jump_break:  # (payload array byte)
34735     0x11/imm32/alloc-id:fake:payload
34736     # "0f 85/jump-if-!= break/disp32"
34737     0x1d/imm32/size
34738     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
34739 _string_0f_85_jump_loop:  # (payload array byte)
34740     0x11/imm32/alloc-id:fake:payload
34741     # "0f 85/jump-if-!= loop/disp32"
34742     0x1c/imm32/size
34743     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
34744 _string_0f_86_jump_label:  # (payload array byte)
34745     0x11/imm32/alloc-id:fake:payload
34746     # "0f 86/jump-if-addr<="
34747     0x14/imm32/size
34748     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/=
34749 _string_0f_86_jump_break:  # (payload array byte)
34750     0x11/imm32/alloc-id:fake:payload
34751     # "0f 86/jump-if-addr<= break/disp32"
34752     0x21/imm32/size
34753     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
34754 _string_0f_86_jump_loop:  # (payload array byte)
34755     0x11/imm32/alloc-id:fake:payload
34756     # "0f 86/jump-if-addr<= loop/disp32"
34757     0x20/imm32/size
34758     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
34759 _string_0f_87_jump_label:  # (payload array byte)
34760     0x11/imm32/alloc-id:fake:payload
34761     # "0f 87/jump-if-addr>"
34762     0x13/imm32/size
34763     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/>
34764 _string_0f_87_jump_break:  # (payload array byte)
34765     0x11/imm32/alloc-id:fake:payload
34766     # "0f 87/jump-if-addr> break/disp32"
34767     0x20/imm32/size
34768     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
34769 _string_0f_87_jump_loop:  # (payload array byte)
34770     0x11/imm32/alloc-id:fake:payload
34771     # "0f 87/jump-if-addr> loop/disp32"
34772     0x1f/imm32/size
34773     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
34774 _string_0f_8c_jump_label:  # (payload array byte)
34775     0x11/imm32/alloc-id:fake:payload
34776     # "0f 8c/jump-if-<"
34777     0xf/imm32/size
34778     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/<
34779 _string_0f_8c_jump_break:  # (payload array byte)
34780     0x11/imm32/alloc-id:fake:payload
34781     # "0f 8c/jump-if-< break/disp32"
34782     0x1c/imm32/size
34783     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
34784 _string_0f_8c_jump_loop:  # (payload array byte)
34785     0x11/imm32/alloc-id:fake:payload
34786     # "0f 8c/jump-if-< loop/disp32"
34787     0x1b/imm32/size
34788     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
34789 _string_0f_8d_jump_label:  # (payload array byte)
34790     0x11/imm32/alloc-id:fake:payload
34791     # "0f 8d/jump-if->="
34792     0x10/imm32/size
34793     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/=
34794 _string_0f_8d_jump_break:  # (payload array byte)
34795     0x11/imm32/alloc-id:fake:payload
34796     # "0f 8d/jump-if->= break/disp32"
34797     0x1d/imm32/size
34798     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
34799 _string_0f_8d_jump_loop:  # (payload array byte)
34800     0x11/imm32/alloc-id:fake:payload
34801     # "0f 8d/jump-if->= loop/disp32"
34802     0x1c/imm32/size
34803     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
34804 _string_0f_8e_jump_label:  # (payload array byte)
34805     0x11/imm32/alloc-id:fake:payload
34806     # "0f 8e/jump-if-<="
34807     0x10/imm32/size
34808     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/=
34809 _string_0f_8e_jump_break:  # (payload array byte)
34810     0x11/imm32/alloc-id:fake:payload
34811     # "0f 8e/jump-if-<= break/disp32"
34812     0x1d/imm32/size
34813     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
34814 _string_0f_8e_jump_loop:  # (payload array byte)
34815     0x11/imm32/alloc-id:fake:payload
34816     # "0f 8e/jump-if-<= loop/disp32"
34817     0x1c/imm32/size
34818     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
34819 _string_0f_8f_jump_label:  # (payload array byte)
34820     0x11/imm32/alloc-id:fake:payload
34821     # "0f 8f/jump-if->"
34822     0xf/imm32/size
34823     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/>
34824 _string_0f_8f_jump_break:  # (payload array byte)
34825     0x11/imm32/alloc-id:fake:payload
34826     # "0f 8f/jump-if-> break/disp32"
34827     0x1c/imm32/size
34828     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
34829 _string_0f_8f_jump_loop:  # (payload array byte)
34830     0x11/imm32/alloc-id:fake:payload
34831     # "0f 8f/jump-if-> loop/disp32"
34832     0x1b/imm32/size
34833     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
34834 _string_0f_af_multiply:  # (payload array byte)
34835     0x11/imm32/alloc-id:fake:payload
34836     # "0f af/multiply"
34837     0xe/imm32/size
34838     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
34839 _string_f3_0f_2a_convert_to_float:
34840     0x11/imm32/alloc-id:fake:payload
34841     # "f3 0f 2a/convert-to-float"
34842     0x19/imm32/size
34843     0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x32/2 0x61/a 0x2f/slash 0x63/c 0x6f/o 0x6e/n 0x76/v 0x65/e 0x72/r 0x74/t 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x66/f 0x6c/l 0x6f/o 0x61/a 0x74/t
34844 _string_f3_0f_2d_convert_to_int:
34845     0x11/imm32/alloc-id:fake:payload
34846     # "f3 0f 2d/convert-to-int"
34847     0x17/imm32/size
34848     0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x32/2 0x64/d 0x2f/slash 0x63/c 0x6f/o 0x6e/n 0x76/v 0x65/e 0x72/r 0x74/t 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x69/i 0x6e/n 0x74/t
34849 _string_f3_0f_2c_truncate_to_int:
34850     0x11/imm32/alloc-id:fake:payload
34851     # "f3 0f 2c/truncate-to-int"
34852     0x18/imm32/size
34853     0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x32/2 0x63/c 0x2f/slash 0x74/t 0x72/r 0x75/u 0x6e/n 0x63/c 0x61/a 0x74/t 0x65/e 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x69/i 0x6e/n 0x74/t
34854 _string_f3_0f_58_add:
34855     0x11/imm32/alloc-id:fake:payload
34856     # "f3 0f 58/add"
34857     0xc/imm32/size
34858     0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x35/5 0x38/8 0x2f/slash 0x61/a 0x64/d 0x64/d
34859 _string_f3_0f_5c_subtract:
34860     0x11/imm32/alloc-id:fake:payload
34861     # "f3 0f 5c/subtract"
34862     0x11/imm32/size
34863     0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x35/5 0x63/c 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
34864 _string_f3_0f_59_multiply:
34865     0x11/imm32/alloc-id:fake:payload
34866     # "f3 0f 59/multiply"
34867     0x11/imm32/size
34868     0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x35/5 0x39/9 0x2f/slash 0x6d/m 0x75/u 0x6c/l 0x74/t 0x69/i 0x70/p 0x6c/l 0x79/y
34869 _string_f3_0f_5e_divide:
34870     0x11/imm32/alloc-id:fake:payload
34871     # "f3 0f 5e/divide"
34872     0xf/imm32/size
34873     0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x35/5 0x65/e 0x2f/slash 0x64/d 0x69/i 0x76/v 0x69/i 0x64/d 0x65/e
34874 _string_f3_0f_53_reciprocal:
34875     0x11/imm32/alloc-id:fake:payload
34876     # "f3 0f 53/reciprocal"
34877     0x13/imm32/size
34878     0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x35/5 0x33/3 0x2f/slash 0x72/r 0x65/e 0x63/c 0x69/i 0x70/p 0x72/r 0x6f/o 0x63/c 0x61/a 0x6c/l
34879 _string_f3_0f_51_square_root:
34880     0x11/imm32/alloc-id:fake:payload
34881     # "f3 0f 51/square-root"
34882     0x14/imm32/size
34883     0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x35/5 0x31/1 0x2f/slash 0x73/s 0x71/q 0x75/u 0x61/a 0x72/r 0x65/e 0x2d/dash 0x72/r 0x6f/o 0x6f/o 0x74/t
34884 _string_f3_0f_52_inverse_square_root:
34885     0x11/imm32/alloc-id:fake:payload
34886     # "f3 0f 52/inverse-square-root"
34887     0x1c/imm32/size
34888     0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x35/5 0x32/2 0x2f/slash 0x69/i 0x6e/n 0x76/v 0x65/e 0x72/r 0x73/s 0x65/e 0x2d/dash 0x73/s 0x71/q 0x75/u 0x61/a 0x72/r 0x65/e 0x2d/dash 0x72/r 0x6f/o 0x6f/o 0x74/t
34889 _string_f3_0f_5d_min:
34890     0x11/imm32/alloc-id:fake:payload
34891     # "f3 0f 5d/min"
34892     0xc/imm32/size
34893     0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x35/5 0x64/d 0x2f/slash 0x6d/m 0x69/i 0x6e/n
34894 _string_f3_0f_5f_max:
34895     0x11/imm32/alloc-id:fake:payload
34896     # "f3 0f 5f/max"
34897     0xc/imm32/size
34898     0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x35/5 0x66/f 0x2f/slash 0x6d/m 0x61/a 0x78/x
34899 _string_f3_0f_10_copy:
34900     0x11/imm32/alloc-id:fake:payload
34901     # "f3 0f 10/copy"
34902     0xd/imm32/size
34903     0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x31/1 0x30/0 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y
34904 _string_f3_0f_11_copy:
34905     0x11/imm32/alloc-id:fake:payload
34906     # "f3 0f 11/copy"
34907     0xd/imm32/size
34908     0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x31/1 0x31/1 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y
34909 _string_0f_2f_compare:
34910     0x11/imm32/alloc-id:fake:payload
34911     # "0f 2f/compare"
34912     0xd/imm32/size
34913     0x30/0 0x66/f 0x20/space 0x32/2 0x66/f 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e
34914 _string_21_and_with:  # (payload array byte)
34915     0x11/imm32/alloc-id:fake:payload
34916     # "21/and-with"
34917     0xb/imm32/size
34918     0x32/2 0x31/1 0x2f/slash 0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
34919 _string_23_and:  # (payload array byte)
34920     0x11/imm32/alloc-id:fake:payload
34921     # "23/and"
34922     0x6/imm32/size
34923     0x32/2 0x33/3 0x2f/slash 0x61/a 0x6e/n 0x64/d
34924 _string_25_and_with_eax:  # (payload array byte)
34925     0x11/imm32/alloc-id:fake:payload
34926     # "25/and-with-eax"
34927     0xf/imm32/size
34928     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
34929 _string_29_subtract_from:  # (payload array byte)
34930     0x11/imm32/alloc-id:fake:payload
34931     # "29/subtract-from"
34932     0x10/imm32/size
34933     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
34934 _string_2b_subtract:  # (payload array byte)
34935     0x11/imm32/alloc-id:fake:payload
34936     # "2b/subtract"
34937     0xb/imm32/size
34938     0x32/2 0x62/b 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
34939 _string_2d_subtract_from_eax:  # (payload array byte)
34940     0x11/imm32/alloc-id:fake:payload
34941     # "2d/subtract-from-eax"
34942     0x14/imm32/size
34943     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
34944 _string_31_xor_with:  # (payload array byte)
34945     0x11/imm32/alloc-id:fake:payload
34946     # "31/xor-with"
34947     0xb/imm32/size
34948     0x33/3 0x31/1 0x2f/slash 0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
34949 _string_33_xor:  # (payload array byte)
34950     0x11/imm32/alloc-id:fake:payload
34951     # "33/xor"
34952     0x6/imm32/size
34953     0x33/3 0x33/3 0x2f/slash 0x78/x 0x6f/o 0x72/r
34954 _string_35_xor_with_eax:  # (payload array byte)
34955     0x11/imm32/alloc-id:fake:payload
34956     # "35/xor-with-eax"
34957     0xf/imm32/size
34958     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
34959 _string_39_compare->:  # (payload array byte)
34960     0x11/imm32/alloc-id:fake:payload
34961     # "39/compare->"
34962     0xc/imm32/size
34963     0x33/3 0x39/9 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x2d/dash 0x3e/>
34964 _string_3b_compare<-:  # (payload array byte)
34965     0x11/imm32/alloc-id:fake:payload
34966     # "3b/compare<-"
34967     0xc/imm32/size
34968     0x33/3 0x62/b 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x3c/< 0x2d/dash
34969 _string_3d_compare_eax_with:  # (payload array byte)
34970     0x11/imm32/alloc-id:fake:payload
34971     # "3d/compare-eax-with"
34972     0x13/imm32/size
34973     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
34974 _string_40_increment_eax:  # (payload array byte)
34975     0x11/imm32/alloc-id:fake:payload
34976     # "40/increment-eax"
34977     0x10/imm32/size
34978     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
34979 _string_41_increment_ecx:  # (payload array byte)
34980     0x11/imm32/alloc-id:fake:payload
34981     # "41/increment-ecx"
34982     0x10/imm32/size
34983     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
34984 _string_42_increment_edx:  # (payload array byte)
34985     0x11/imm32/alloc-id:fake:payload
34986     # "42/increment-edx"
34987     0x10/imm32/size
34988     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
34989 _string_43_increment_ebx:  # (payload array byte)
34990     0x11/imm32/alloc-id:fake:payload
34991     # "43/increment-ebx"
34992     0x10/imm32/size
34993     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
34994 _string_46_increment_esi:  # (payload array byte)
34995     0x11/imm32/alloc-id:fake:payload
34996     # "46/increment-esi"
34997     0x10/imm32/size
34998     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
34999 _string_47_increment_edi:  # (payload array byte)
35000     0x11/imm32/alloc-id:fake:payload
35001     # "47/increment-edi"
35002     0x10/imm32/size
35003     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
35004 _string_48_decrement_eax:  # (payload array byte)
35005     0x11/imm32/alloc-id:fake:payload
35006     # "48/decrement-eax"
35007     0x10/imm32/size
35008     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
35009 _string_49_decrement_ecx:  # (payload array byte)
35010     0x11/imm32/alloc-id:fake:payload
35011     # "49/decrement-ecx"
35012     0x10/imm32/size
35013     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
35014 _string_4a_decrement_edx:  # (payload array byte)
35015     0x11/imm32/alloc-id:fake:payload
35016     # "4a/decrement-edx"
35017     0x10/imm32/size
35018     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
35019 _string_4b_decrement_ebx:  # (payload array byte)
35020     0x11/imm32/alloc-id:fake:payload
35021     # "4b/decrement-ebx"
35022     0x10/imm32/size
35023     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
35024 _string_4e_decrement_esi:  # (payload array byte)
35025     0x11/imm32/alloc-id:fake:payload
35026     # "4e/decrement-esi"
35027     0x10/imm32/size
35028     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
35029 _string_4f_decrement_edi:  # (payload array byte)
35030     0x11/imm32/alloc-id:fake:payload
35031     # "4f/decrement-edi"
35032     0x10/imm32/size
35033     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
35034 _string_81_subop_add:  # (payload array byte)
35035     0x11/imm32/alloc-id:fake:payload
35036     # "81 0/subop/add"
35037     0xe/imm32/size
35038     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
35039 _string_81_subop_or:  # (payload array byte)
35040     0x11/imm32/alloc-id:fake:payload
35041     # "81 1/subop/or"
35042     0xd/imm32/size
35043     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
35044 _string_81_subop_and:  # (payload array byte)
35045     0x11/imm32/alloc-id:fake:payload
35046     # "81 4/subop/and"
35047     0xe/imm32/size
35048     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
35049 _string_81_subop_subtract:  # (payload array byte)
35050     0x11/imm32/alloc-id:fake:payload
35051     # "81 5/subop/subtract"
35052     0x13/imm32/size
35053     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
35054 _string_81_subop_xor:  # (payload array byte)
35055     0x11/imm32/alloc-id:fake:payload
35056     # "81 6/subop/xor"
35057     0xe/imm32/size
35058     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
35059 _string_81_subop_compare:  # (payload array byte)
35060     0x11/imm32/alloc-id:fake:payload
35061     # "81 7/subop/compare"
35062     0x12/imm32/size
35063     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
35064 _string_89_<-:  # (payload array byte)
35065     0x11/imm32/alloc-id:fake:payload
35066     # "89/<-"
35067     0x5/imm32/size
35068     0x38/8 0x39/9 0x2f/slash 0x3c/< 0x2d/dash
35069 _string_8b_->:  # (payload array byte)
35070     0x11/imm32/alloc-id:fake:payload
35071     # "8b/->"
35072     0x5/imm32/size
35073     0x38/8 0x62/b 0x2f/slash 0x2d/dash 0x3e/>
35074 _string_8a_copy_byte:
35075     0x11/imm32/alloc-id:fake:payload
35076     # "8a/byte->"
35077     0x9/imm32/size
35078     0x38/8 0x61/a 0x2f/slash 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/dash 0x3e/>
35079 _string_88_copy_byte:
35080     0x11/imm32/alloc-id:fake:payload
35081     # "88/byte<-"
35082     0x9/imm32/size
35083     0x38/8 0x38/8 0x2f/slash 0x62/b 0x79/y 0x74/t 0x65/e 0x3c/< 0x2d/-
35084 _string_8d_copy_address:  # (payload array byte)
35085     0x11/imm32/alloc-id:fake:payload
35086     # "8d/copy-address"
35087     0xf/imm32/size
35088     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
35089 _string_b8_copy_to_eax:  # (payload array byte)
35090     0x11/imm32/alloc-id:fake:payload
35091     # "b8/copy-to-eax"
35092     0xe/imm32/size
35093     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
35094 _string_b9_copy_to_ecx:  # (payload array byte)
35095     0x11/imm32/alloc-id:fake:payload
35096     # "b9/copy-to-ecx"
35097     0xe/imm32/size
35098     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
35099 _string_ba_copy_to_edx:  # (payload array byte)
35100     0x11/imm32/alloc-id:fake:payload
35101     # "ba/copy-to-edx"
35102     0xe/imm32/size
35103     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
35104 _string_bb_copy_to_ebx:  # (payload array byte)
35105     0x11/imm32/alloc-id:fake:payload
35106     # "bb/copy-to-ebx"
35107     0xe/imm32/size
35108     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
35109 _string_be_copy_to_esi:  # (payload array byte)
35110     0x11/imm32/alloc-id:fake:payload
35111     # "be/copy-to-esi"
35112     0xe/imm32/size
35113     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
35114 _string_bf_copy_to_edi:  # (payload array byte)
35115     0x11/imm32/alloc-id:fake:payload
35116     # "bf/copy-to-edi"
35117     0xe/imm32/size
35118     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
35119 _string_c7_subop_copy:  # (payload array byte)
35120     0x11/imm32/alloc-id:fake:payload
35121     # "c7 0/subop/copy"
35122     0xf/imm32/size
35123     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
35124 _string_e9_jump_label:  # (payload array byte)
35125     0x11/imm32/alloc-id:fake:payload
35126     # "e9/jump"
35127     0x7/imm32/size
35128     0x65/e 0x39/9 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p
35129 _string_e9_jump_break:  # (payload array byte)
35130     0x11/imm32/alloc-id:fake:payload
35131     # "e9/jump break/disp32"
35132     0x14/imm32/size
35133     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
35134 _string_e9_jump_loop:  # (payload array byte)
35135     0x11/imm32/alloc-id:fake:payload
35136     # "e9/jump loop/disp32"
35137     0x13/imm32/size
35138     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
35139 _string_f7_subop_negate:
35140     0x11/imm32/alloc-id:fake:payload
35141     # "f7 3/subop/negate"
35142     0x11/imm32/size
35143     0x66/f 0x37/7 0x20/space 0x33/3 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x6e/n 0x65/e 0x67/g 0x61/a 0x74/t 0x65/e
35144 _string_f7_subop_not:
35145     0x11/imm32/alloc-id:fake:payload
35146     # "f7 2/subop/not"
35147     0xe/imm32/size
35148     0x66/f 0x37/7 0x20/space 0x32/2 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x6e/n 0x6f/o 0x74/t
35149 _string_ff_subop_increment:  # (payload array byte)
35150     0x11/imm32/alloc-id:fake:payload
35151     # "ff 0/subop/increment"
35152     0x14/imm32/size
35153     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
35154 _string_ff_subop_decrement:  # (payload array byte)
35155     0x11/imm32/alloc-id:fake:payload
35156     # "ff 1/subop/decrement"
35157     0x14/imm32/size
35158     0x66/f 0x66/f 0x20/space 0x31/1 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
35159 _string_c1_subop_shift_left:  # (payload array byte)
35160     0x11/imm32/alloc-id:fake:payload
35161     # "c1/shift 4/subop/left"
35162     0x15/imm32/size
35163     0x63/c 0x31/1 0x2f/slash 0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x20/space 0x34/4 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x6c/l 0x65/e 0x66/f 0x74/t
35164 _string_c1_subop_shift_right_padding_zeroes:  # (payload array byte)
35165     0x11/imm32/alloc-id:fake:payload
35166     # "c1/shift 5/subop/right-padding-zeroes"
35167     0x25/imm32/size
35168     0x63/c 0x31/1 0x2f/slash 0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x20/space 0x35/5 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x72/r 0x69/i 0x67/g 0x68/h 0x74/t 0x2d/dash 0x70/p 0x61/a 0x64/d 0x64/d 0x69/i 0x6e/n 0x67/g 0x2d/dash 0x7a/z 0x65/e 0x72/r 0x6f/o 0x65/e 0x73/s
35169 _string_c1_subop_shift_right_preserving_sign:  # (payload array byte)
35170     0x11/imm32/alloc-id:fake:payload
35171     # "c1/shift 7/subop/right-preserving-sign"
35172     0x26/imm32/size
35173     0x63/c 0x31/1 0x2f/slash 0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x20/space 0x37/7 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x72/r 0x69/i 0x67/g 0x68/h 0x74/t 0x2d/dash 0x70/p 0x72/r 0x65/e 0x73/s 0x65/e 0x72/r 0x76/v 0x69/i 0x6e/n 0x67/g 0x2d/dash 0x73/s 0x69/i 0x67/g 0x6e/n
35175 Single-int-var-in-mem:  # (payload list var)
35176     0x11/imm32/alloc-id:fake:payload
35177     0x11/imm32/alloc-id:fake
35178     Int-var-in-mem/imm32
35179     0/imm32/next
35180     0/imm32/next
35182 Int-var-in-mem:  # (payload var)
35183     0x11/imm32/alloc-id:fake:payload
35184     0/imm32/name
35185     0/imm32/name
35186     0x11/imm32/alloc-id:fake
35187     Type-int/imm32
35188     1/imm32/some-block-depth
35189     1/imm32/some-stack-offset
35190     0/imm32/no-register
35191     0/imm32/no-register
35193 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
35194 Single-byte-var-in-mem:  # (payload list var)
35195     0x11/imm32/alloc-id:fake:payload
35196     0x11/imm32/alloc-id:fake
35197     Byte-var-in-mem/imm32
35198     0/imm32/next
35199     0/imm32/next
35201 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
35202 Byte-var-in-mem:  # (payload var)
35203     0x11/imm32/alloc-id:fake:payload
35204     0/imm32/name
35205     0/imm32/name
35206     0x11/imm32/alloc-id:fake
35207     Type-byte/imm32
35208     1/imm32/some-block-depth
35209     1/imm32/some-stack-offset
35210     0/imm32/no-register
35211     0/imm32/no-register
35213 Two-args-int-stack-int-reg:  # (payload list var)
35214     0x11/imm32/alloc-id:fake:payload
35215     0x11/imm32/alloc-id:fake
35216     Int-var-in-mem/imm32
35217     0x11/imm32/alloc-id:fake
35218     Single-int-var-in-some-register/imm32/next
35220 Two-int-args-in-regs:  # (payload list var)
35221     0x11/imm32/alloc-id:fake:payload
35222     0x11/imm32/alloc-id:fake
35223     Int-var-in-some-register/imm32
35224     0x11/imm32/alloc-id:fake
35225     Single-int-var-in-some-register/imm32/next
35227 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
35228 Two-args-byte-stack-byte-reg:  # (payload list var)
35229     0x11/imm32/alloc-id:fake:payload
35230     0x11/imm32/alloc-id:fake
35231     Byte-var-in-mem/imm32
35232     0x11/imm32/alloc-id:fake
35233     Single-byte-var-in-some-register/imm32/next
35235 Two-args-int-reg-int-stack:  # (payload list var)
35236     0x11/imm32/alloc-id:fake:payload
35237     0x11/imm32/alloc-id:fake
35238     Int-var-in-some-register/imm32
35239     0x11/imm32/alloc-id:fake
35240     Single-int-var-in-mem/imm32/next
35242 Two-args-int-eax-int-literal:  # (payload list var)
35243     0x11/imm32/alloc-id:fake:payload
35244     0x11/imm32/alloc-id:fake
35245     Int-var-in-eax/imm32
35246     0x11/imm32/alloc-id:fake
35247     Single-lit-var/imm32/next
35249 Int-var-and-literal:  # (payload list var)
35250     0x11/imm32/alloc-id:fake:payload
35251     0x11/imm32/alloc-id:fake
35252     Int-var-in-mem/imm32
35253     0x11/imm32/alloc-id:fake
35254     Single-lit-var/imm32/next
35256 Int-var-in-register-and-literal:  # (payload list var)
35257     0x11/imm32/alloc-id:fake:payload
35258     0x11/imm32/alloc-id:fake
35259     Int-var-in-some-register/imm32
35260     0x11/imm32/alloc-id:fake
35261     Single-lit-var/imm32/next
35263 Two-float-args-in-regs:  # (payload list var)
35264     0x11/imm32/alloc-id:fake:payload
35265     0x11/imm32/alloc-id:fake
35266     Float-var-in-some-register/imm32
35267     0x11/imm32/alloc-id:fake
35268     Single-float-var-in-some-register/imm32/next
35270 Two-args-float-reg-float-stack:  # (payload list var)
35271     0x11/imm32/alloc-id:fake:payload
35272     0x11/imm32/alloc-id:fake
35273     Float-var-in-some-register/imm32
35274     0x11/imm32/alloc-id:fake
35275     Single-float-var-in-mem/imm32/next
35277 Two-args-float-stack-float-reg:  # (payload list var)
35278     0x11/imm32/alloc-id:fake:payload
35279     0x11/imm32/alloc-id:fake
35280     Float-var-in-mem/imm32
35281     0x11/imm32/alloc-id:fake
35282     Single-float-var-in-some-register/imm32/next
35284 Single-int-var-in-some-register:  # (payload list var)
35285     0x11/imm32/alloc-id:fake:payload
35286     0x11/imm32/alloc-id:fake
35287     Int-var-in-some-register/imm32
35288     0/imm32/next
35289     0/imm32/next
35291 Single-addr-var-in-some-register:  # (payload list var)
35292     0x11/imm32/alloc-id:fake:payload
35293     0x11/imm32/alloc-id:fake
35294     Addr-var-in-some-register/imm32
35295     0/imm32/next
35296     0/imm32/next
35298 Single-byte-var-in-some-register:  # (payload list var)
35299     0x11/imm32/alloc-id:fake:payload
35300     0x11/imm32/alloc-id:fake
35301     Byte-var-in-some-register/imm32
35302     0/imm32/next
35303     0/imm32/next
35305 Int-var-in-some-register:  # (payload var)
35306     0x11/imm32/alloc-id:fake:payload
35307     0/imm32/name
35308     0/imm32/name
35309     0x11/imm32/alloc-id:fake
35310     Type-int/imm32
35311     1/imm32/some-block-depth
35312     0/imm32/no-stack-offset
35313     0x11/imm32/alloc-id:fake
35314     Any-register/imm32
35316 Any-register:  # (payload array byte)
35317     0x11/imm32/alloc-id:fake:payload
35318     1/imm32/size
35319     # data
35320     2a/asterisk
35322 Addr-var-in-some-register:  # (payload var)
35323     0x11/imm32/alloc-id:fake:payload
35324     0/imm32/name
35325     0/imm32/name
35326     0x11/imm32/alloc-id:fake
35327     Type-addr/imm32
35328     1/imm32/some-block-depth
35329     0/imm32/no-stack-offset
35330     0x11/imm32/alloc-id:fake
35331     Any-register/imm32
35333 Byte-var-in-some-register:  # (payload var)
35334     0x11/imm32/alloc-id:fake:payload
35335     0/imm32/name
35336     0/imm32/name
35337     0x11/imm32/alloc-id:fake
35338     Type-byte/imm32
35339     1/imm32/some-block-depth
35340     0/imm32/no-stack-offset
35341     0x11/imm32/alloc-id:fake
35342     Any-register/imm32
35344 Single-int-var-in-eax:  # (payload list var)
35345     0x11/imm32/alloc-id:fake:payload
35346     0x11/imm32/alloc-id:fake
35347     Int-var-in-eax/imm32
35348     0/imm32/next
35349     0/imm32/next
35351 Int-var-in-eax:
35352     0x11/imm32/alloc-id:fake:payload
35353     0/imm32/name
35354     0/imm32/name
35355     0x11/imm32/alloc-id:fake
35356     Type-int/imm32
35357     1/imm32/some-block-depth
35358     0/imm32/no-stack-offset
35359     0x11/imm32/alloc-id:fake
35360     $Mu-register-eax/imm32  # can't use Register-eax only to keep our buggy tools/treeshake.cc happy (TODO)
35362 Single-int-var-in-ecx:  # (payload list var)
35363     0x11/imm32/alloc-id:fake:payload
35364     0x11/imm32/alloc-id:fake
35365     Int-var-in-ecx/imm32
35366     0/imm32/next
35367     0/imm32/next
35369 Int-var-in-ecx:
35370     0x11/imm32/alloc-id:fake:payload
35371     0/imm32/name
35372     0/imm32/name
35373     0x11/imm32/alloc-id:fake
35374     Type-int/imm32
35375     1/imm32/some-block-depth
35376     0/imm32/no-stack-offset
35377     0x11/imm32/alloc-id:fake
35378     $Register-ecx/imm32/register
35380 Single-int-var-in-edx:  # (payload list var)
35381     0x11/imm32/alloc-id:fake:payload
35382     0x11/imm32/alloc-id:fake
35383     Int-var-in-edx/imm32
35384     0/imm32/next
35385     0/imm32/next
35387 Int-var-in-edx:  # (payload list var)
35388     0x11/imm32/alloc-id:fake:payload
35389     0/imm32/name
35390     0/imm32/name
35391     0x11/imm32/alloc-id:fake
35392     Type-int/imm32
35393     1/imm32/some-block-depth
35394     0/imm32/no-stack-offset
35395     0x11/imm32/alloc-id:fake
35396     $Register-edx/imm32/register
35398 Single-int-var-in-ebx:  # (payload list var)
35399     0x11/imm32/alloc-id:fake:payload
35400     0x11/imm32/alloc-id:fake
35401     Int-var-in-ebx/imm32
35402     0/imm32/next
35403     0/imm32/next
35405 Int-var-in-ebx:  # (payload list var)
35406     0x11/imm32/alloc-id:fake:payload
35407     0/imm32/name
35408     0/imm32/name
35409     0x11/imm32/alloc-id:fake
35410     Type-int/imm32
35411     1/imm32/some-block-depth
35412     0/imm32/no-stack-offset
35413     0x11/imm32/alloc-id:fake
35414     $Register-ebx/imm32/register
35416 Single-int-var-in-esi:  # (payload list var)
35417     0x11/imm32/alloc-id:fake:payload
35418     0x11/imm32/alloc-id:fake
35419     Int-var-in-esi/imm32
35420     0/imm32/next
35421     0/imm32/next
35423 Int-var-in-esi:  # (payload list var)
35424     0x11/imm32/alloc-id:fake:payload
35425     0/imm32/name
35426     0/imm32/name
35427     0x11/imm32/alloc-id:fake
35428     Type-int/imm32
35429     1/imm32/some-block-depth
35430     0/imm32/no-stack-offset
35431     0x11/imm32/alloc-id:fake
35432     $Register-esi/imm32/register
35434 Single-int-var-in-edi:  # (payload list var)
35435     0x11/imm32/alloc-id:fake:payload
35436     0x11/imm32/alloc-id:fake
35437     Int-var-in-edi/imm32
35438     0/imm32/next
35439     0/imm32/next
35441 Int-var-in-edi:  # (payload list var)
35442     0x11/imm32/alloc-id:fake:payload
35443     0/imm32/name
35444     0/imm32/name
35445     0x11/imm32/alloc-id:fake
35446     Type-int/imm32
35447     1/imm32/some-block-depth
35448     0/imm32/no-stack-offset
35449     0x11/imm32/alloc-id:fake
35450     $Register-edi/imm32/register
35452 Single-lit-var:  # (payload list var)
35453     0x11/imm32/alloc-id:fake:payload
35454     0x11/imm32/alloc-id:fake
35455     Lit-var/imm32
35456     0/imm32/next
35457     0/imm32/next
35459 Lit-var:  # (payload var)
35460     0x11/imm32/alloc-id:fake:payload
35461     0/imm32/name
35462     0/imm32/name
35463     0x11/imm32/alloc-id:fake
35464     Type-literal/imm32
35465     1/imm32/some-block-depth
35466     0/imm32/no-stack-offset
35467     0/imm32/no-register
35468     0/imm32/no-register
35470 Single-float-var-in-mem:  # (payload list var)
35471     0x11/imm32/alloc-id:fake:payload
35472     0x11/imm32/alloc-id:fake
35473     Float-var-in-mem/imm32
35474     0/imm32/next
35475     0/imm32/next
35477 Float-var-in-mem:  # (payload var)
35478     0x11/imm32/alloc-id:fake:payload
35479     0/imm32/name
35480     0/imm32/name
35481     0x11/imm32/alloc-id:fake
35482     Type-float/imm32
35483     1/imm32/some-block-depth
35484     1/imm32/some-stack-offset
35485     0/imm32/no-register
35486     0/imm32/no-register
35488 Single-float-var-in-some-register:  # (payload list var)
35489     0x11/imm32/alloc-id:fake:payload
35490     0x11/imm32/alloc-id:fake
35491     Float-var-in-some-register/imm32
35492     0/imm32/next
35493     0/imm32/next
35495 Float-var-in-some-register:  # (payload var)
35496     0x11/imm32/alloc-id:fake:payload
35497     0/imm32/name
35498     0/imm32/name
35499     0x11/imm32/alloc-id:fake
35500     Type-float/imm32
35501     1/imm32/some-block-depth
35502     0/imm32/no-stack-offset
35503     0x11/imm32/alloc-id:fake
35504     Any-register/imm32
35506 Type-int:  # (payload type-tree)
35507     0x11/imm32/alloc-id:fake:payload
35508     1/imm32/is-atom
35509     1/imm32/value:int
35510     0/imm32/left:unused
35511     0/imm32/right:null
35512     0/imm32/right:null
35514 Type-literal:  # (payload type-tree)
35515     0x11/imm32/alloc-id:fake:payload
35516     1/imm32/is-atom
35517     0/imm32/value:literal
35518     0/imm32/left:unused
35519     0/imm32/right:null
35520     0/imm32/right:null
35522 Type-addr:  # (payload type-tree)
35523     0x11/imm32/alloc-id:fake:payload
35524     1/imm32/is-atom
35525     2/imm32/value:addr
35526     0/imm32/left:unused
35527     0/imm32/right:null
35528     0/imm32/right:null
35530 Type-array:  # (payload type-tree)
35531     0x11/imm32/alloc-id:fake:payload
35532     1/imm32/is-atom
35533     3/imm32/value:array
35534     0/imm32/left:unused
35535     0/imm32/right:null
35536     0/imm32/right:null
35538 Type-byte:  # (payload type-tree)
35539     0x11/imm32/alloc-id:fake:payload
35540     1/imm32/is-atom
35541     8/imm32/value:byte
35542     0/imm32/left:unused
35543     0/imm32/right:null
35544     0/imm32/right:null
35546 Type-float:  # (payload type-tree)
35547     0x11/imm32/alloc-id:fake:payload
35548     1/imm32/is-atom
35549     0xf/imm32/value:float
35550     0/imm32/left:unused
35551     0/imm32/right:null
35552     0/imm32/right:null
35554 Addr-type-string:  # (addr type-tree)
35555   0/imm32/not-atom
35556   0x11/imm32/alloc-id:fake
35557   Type-addr/imm32/left
35558   0x11/imm32/alloc-id:fake
35559   _Addr-type-string:array/imm32/right
35560 _Addr-type-string:array:  # (payload type-tree)
35561   0x11/imm32/alloc-id:fake:payload
35562   0/imm32/not-atom
35563   0x11/imm32/alloc-id:fake
35564   Type-array/imm32/left
35565   0x11/imm32/alloc-id:fake
35566   _Addr-type-string:byte/imm32/right
35567 _Addr-type-string:byte:  # (payload type-tree)
35568   0x11/imm32/alloc-id:fake:payload
35569   0/imm32/not-atom
35570   0x11/imm32/alloc-id:fake
35571   Type-byte/imm32/left
35572   0/imm32/right:null
35573   0/imm32/right:null
35575 == code
35576 emit-subx-primitive:  # out: (addr buffered-file), stmt: (addr stmt), primitive: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
35577     # . prologue
35578     55/push-ebp
35579     89/<- %ebp 4/r32/esp
35580     # . save registers
35581     50/push-eax
35582     51/push-ecx
35583     # ecx = primitive
35584     8b/-> *(ebp+0x10) 1/r32/ecx
35585     # emit primitive name
35586     (emit-indent *(ebp+8) *Curr-block-depth)
35587     (lookup *(ecx+0x18) *(ecx+0x1c))  # Primitive-subx-name Primitive-subx-name => eax
35588     (write-buffered *(ebp+8) %eax)
35589     # emit rm32 if necessary
35590     (emit-subx-rm32 *(ebp+8) *(ecx+0x20) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-rm32
35591     # emit xm32 if necessary
35592     (emit-subx-rm32 *(ebp+8) *(ecx+0x34) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-xm32
35593     # emit r32 if necessary
35594     (emit-subx-r32 *(ebp+8) *(ecx+0x24) *(ebp+0xc))  # Primitive-subx-r32
35595     # emit x32 if necessary
35596     (emit-subx-x32 *(ebp+8) *(ecx+0x38) *(ebp+0xc))  # Primitive-subx-x32
35597     # emit imm32 if necessary
35598     (emit-subx-imm32 *(ebp+8) *(ecx+0x28) *(ebp+0xc))  # Primitive-subx-imm32
35599     # emit imm8 if necessary
35600     (emit-subx-imm8 *(ebp+8) *(ecx+0x2c) *(ebp+0xc))  # Primitive-subx-imm8
35601     # emit disp32 if necessary
35602     (emit-subx-disp32 *(ebp+8) *(ecx+0x30) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-disp32
35603     (write-buffered *(ebp+8) Newline)
35604 $emit-subx-primitive:end:
35605     # . restore registers
35606     59/pop-to-ecx
35607     58/pop-to-eax
35608     # . epilogue
35609     89/<- %esp 5/r32/ebp
35610     5d/pop-to-ebp
35611     c3/return
35613 emit-subx-rm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
35614     # . prologue
35615     55/push-ebp
35616     89/<- %ebp 4/r32/esp
35617     # . save registers
35618     50/push-eax
35619     # if (l == 0) return
35620     81 7/subop/compare *(ebp+0xc) 0/imm32
35621     74/jump-if-= $emit-subx-rm32:end/disp8
35622     # var v/eax: (addr stmt-var)
35623     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
35624     (emit-subx-var-as-rm32 *(ebp+8) %eax)
35625 $emit-subx-rm32:end:
35626     # . restore registers
35627     58/pop-to-eax
35628     # . epilogue
35629     89/<- %esp 5/r32/ebp
35630     5d/pop-to-ebp
35631     c3/return
35633 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)
35634     # . prologue
35635     55/push-ebp
35636     89/<- %ebp 4/r32/esp
35637     # . save registers
35638     51/push-ecx
35639     # eax = l
35640     8b/-> *(ebp+0xc) 0/r32/eax
35641     # ecx = stmt
35642     8b/-> *(ebp+8) 1/r32/ecx
35643     # if (l == 1) return stmt->inouts
35644     {
35645       3d/compare-eax-and 1/imm32
35646       75/jump-if-!= break/disp8
35647 $get-stmt-operand-from-arg-location:1:
35648       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
35649       eb/jump $get-stmt-operand-from-arg-location:end/disp8
35650     }
35651     # if (l == 2) return stmt->inouts->next
35652     {
35653       3d/compare-eax-and 2/imm32
35654       75/jump-if-!= break/disp8
35655 $get-stmt-operand-from-arg-location:2:
35656       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
35657       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
35658       eb/jump $get-stmt-operand-from-arg-location:end/disp8
35659     }
35660     # if (l == 3) return stmt->outputs
35661     {
35662       3d/compare-eax-and 3/imm32
35663       75/jump-if-!= break/disp8
35664 $get-stmt-operand-from-arg-location:3:
35665       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
35666       eb/jump $get-stmt-operand-from-arg-location:end/disp8
35667     }
35668     # abort
35669     e9/jump $get-stmt-operand-from-arg-location:abort/disp32
35670 $get-stmt-operand-from-arg-location:end:
35671     # . restore registers
35672     59/pop-to-ecx
35673     # . epilogue
35674     89/<- %esp 5/r32/ebp
35675     5d/pop-to-ebp
35676     c3/return
35678 $get-stmt-operand-from-arg-location:abort:
35679     # error("invalid arg-location " eax)
35680     (write-buffered *(ebp+0x10) "invalid arg-location ")
35681     (write-int32-hex-buffered *(ebp+0x10) %eax)
35682     (write-buffered *(ebp+0x10) Newline)
35683     (flush *(ebp+0x10))
35684     (stop *(ebp+0x14) 1)
35685     # never gets here
35687 emit-subx-r32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
35688     # . prologue
35689     55/push-ebp
35690     89/<- %ebp 4/r32/esp
35691     # . save registers
35692     50/push-eax
35693     51/push-ecx
35694     # if (l == 0) return
35695     81 7/subop/compare *(ebp+0xc) 0/imm32
35696     0f 84/jump-if-= $emit-subx-r32:end/disp32
35697     # var v/eax: (addr stmt-var)
35698     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
35699     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
35700     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
35701 #?     (write-buffered Stderr "looking up ")
35702 #?     (write-buffered Stderr %eax)
35703 #?     (write-buffered Stderr Newline)
35704 #?     (flush Stderr)
35705     (maybe-get Mu-registers %eax 0xc)  # => eax: (addr register-index)
35706     (write-buffered *(ebp+8) Space)
35707     (write-int32-hex-buffered *(ebp+8) *eax)
35708     (write-buffered *(ebp+8) "/r32")
35709 $emit-subx-r32:end:
35710     # . restore registers
35711     59/pop-to-ecx
35712     58/pop-to-eax
35713     # . epilogue
35714     89/<- %esp 5/r32/ebp
35715     5d/pop-to-ebp
35716     c3/return
35718 emit-subx-x32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
35719     # . prologue
35720     55/push-ebp
35721     89/<- %ebp 4/r32/esp
35722     # . save registers
35723     50/push-eax
35724     51/push-ecx
35725     # if (l == 0) return
35726     81 7/subop/compare *(ebp+0xc) 0/imm32
35727     0f 84/jump-if-= $emit-subx-x32:end/disp32
35728     # var v/eax: (addr stmt-var)
35729     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
35730     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
35731     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
35732 #?     (write-buffered Stderr "looking up ")
35733 #?     (write-buffered Stderr %eax)
35734 #?     (write-buffered Stderr Newline)
35735 #?     (flush Stderr)
35736     (maybe-get Mu-registers %eax 0xc)  # => eax: (addr register-index)
35737     (write-buffered *(ebp+8) Space)
35738     (write-int32-hex-buffered *(ebp+8) *eax)
35739     (write-buffered *(ebp+8) "/x32")
35740 $emit-subx-x32:end:
35741     # . restore registers
35742     59/pop-to-ecx
35743     58/pop-to-eax
35744     # . epilogue
35745     89/<- %esp 5/r32/ebp
35746     5d/pop-to-ebp
35747     c3/return
35749 emit-subx-imm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
35750     # . prologue
35751     55/push-ebp
35752     89/<- %ebp 4/r32/esp
35753     # . save registers
35754     50/push-eax
35755     51/push-ecx
35756     # if (l == 0) return
35757     81 7/subop/compare *(ebp+0xc) 0/imm32
35758     0f 84/jump-if-= $emit-subx-imm32:end/disp32
35759     # var v/eax: (handle var)
35760     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
35761     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
35762     (lookup *eax *(eax+4))  # Var-name Var-name => eax
35763     (write-buffered *(ebp+8) Space)
35764     (write-buffered *(ebp+8) %eax)
35765     (write-buffered *(ebp+8) "/imm32")
35766 $emit-subx-imm32:end:
35767     # . restore registers
35768     59/pop-to-ecx
35769     58/pop-to-eax
35770     # . epilogue
35771     89/<- %esp 5/r32/ebp
35772     5d/pop-to-ebp
35773     c3/return
35775 emit-subx-imm8:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
35776     # . prologue
35777     55/push-ebp
35778     89/<- %ebp 4/r32/esp
35779     # . save registers
35780     50/push-eax
35781     51/push-ecx
35782     # if (l == 0) return
35783     81 7/subop/compare *(ebp+0xc) 0/imm32
35784     0f 84/jump-if-= $emit-subx-imm32:end/disp32
35785     # var v/eax: (handle var)
35786     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
35787     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
35788     (lookup *eax *(eax+4))  # Var-name Var-name => eax
35789     (write-buffered *(ebp+8) Space)
35790     (write-buffered *(ebp+8) %eax)
35791     (write-buffered *(ebp+8) "/imm8")
35792 $emit-subx-imm8:end:
35793     # . restore registers
35794     59/pop-to-ecx
35795     58/pop-to-eax
35796     # . epilogue
35797     89/<- %esp 5/r32/ebp
35798     5d/pop-to-ebp
35799     c3/return
35801 emit-subx-disp32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
35802     # . prologue
35803     55/push-ebp
35804     89/<- %ebp 4/r32/esp
35805     # . save registers
35806     50/push-eax
35807     51/push-ecx
35808     # if (location == 0) return
35809     81 7/subop/compare *(ebp+0xc) 0/imm32
35810     0f 84/jump-if-= $emit-subx-disp32:end/disp32
35811     # var v/eax: (addr stmt-var)
35812     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
35813     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
35814     (lookup *eax *(eax+4))  # Var-name Var-name => eax
35815     (write-buffered *(ebp+8) Space)
35816     (write-buffered *(ebp+8) %eax)
35817     # hack: if instruction operation starts with "break", emit ":break"
35818     # var name/ecx: (addr array byte) = lookup(stmt->operation)
35819     8b/-> *(ebp+0x10) 0/r32/eax
35820     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
35821     89/<- %ecx 0/r32/eax
35822     {
35823       (string-starts-with? %ecx "break")  # => eax
35824       3d/compare-eax-and 0/imm32/false
35825       74/jump-if-= break/disp8
35826       (write-buffered *(ebp+8) ":break")
35827     }
35828     # hack: if instruction operation starts with "loop", emit ":loop"
35829     {
35830       (string-starts-with? %ecx "loop")  # => eax
35831       3d/compare-eax-and 0/imm32/false
35832       74/jump-if-= break/disp8
35833       (write-buffered *(ebp+8) ":loop")
35834     }
35835     (write-buffered *(ebp+8) "/disp32")
35836 $emit-subx-disp32:end:
35837     # . restore registers
35838     59/pop-to-ecx
35839     58/pop-to-eax
35840     # . epilogue
35841     89/<- %esp 5/r32/ebp
35842     5d/pop-to-ebp
35843     c3/return
35845 emit-call:  # out: (addr buffered-file), stmt: (addr stmt)
35846     # . prologue
35847     55/push-ebp
35848     89/<- %ebp 4/r32/esp
35849     # . save registers
35850     50/push-eax
35851     51/push-ecx
35852     #
35853     (emit-indent *(ebp+8) *Curr-block-depth)
35854     (write-buffered *(ebp+8) "(")
35855     # ecx = stmt
35856     8b/-> *(ebp+0xc) 1/r32/ecx
35857     # - emit function name
35858     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
35859     (write-buffered *(ebp+8) %eax)
35860     # - emit arguments
35861     # var curr/eax: (addr stmt-var) = lookup(stmt->inouts)
35862     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
35863     {
35864       # if (curr == null) break
35865       3d/compare-eax-and 0/imm32
35866       74/jump-if-= break/disp8
35867       #
35868       (emit-subx-call-operand *(ebp+8) %eax)
35869       # curr = lookup(curr->next)
35870       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
35871       eb/jump loop/disp8
35872     }
35873     #
35874     (write-buffered *(ebp+8) ")\n")
35875 $emit-call:end:
35876     # . restore registers
35877     59/pop-to-ecx
35878     58/pop-to-eax
35879     # . epilogue
35880     89/<- %esp 5/r32/ebp
35881     5d/pop-to-ebp
35882     c3/return
35884 emit-subx-call-operand:  # out: (addr buffered-file), s: (addr stmt-var)
35885     # shares code with emit-subx-var-as-rm32
35886     # . prologue
35887     55/push-ebp
35888     89/<- %ebp 4/r32/esp
35889     # . save registers
35890     50/push-eax
35891     51/push-ecx
35892     56/push-esi
35893     # ecx = s
35894     8b/-> *(ebp+0xc) 1/r32/ecx
35895     # var operand/esi: (addr var) = lookup(s->value)
35896     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
35897     89/<- %esi 0/r32/eax
35898     # if (operand->register && !s->is-deref?) emit "%__"
35899     {
35900 $emit-subx-call-operand:check-for-register-direct:
35901       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
35902       74/jump-if-= break/disp8
35903       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
35904       75/jump-if-!= break/disp8
35905 $emit-subx-call-operand:register-direct:
35906       (write-buffered *(ebp+8) " %")
35907       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
35908       (write-buffered *(ebp+8) %eax)
35909       e9/jump $emit-subx-call-operand:end/disp32
35910     }
35911     # else if (operand->register && s->is-deref?) emit "*__"
35912     {
35913 $emit-subx-call-operand:check-for-register-indirect:
35914       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
35915       74/jump-if-= break/disp8
35916       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
35917       74/jump-if-= break/disp8
35918 $emit-subx-call-operand:register-indirect:
35919       (emit-subx-call-operand-register-indirect *(ebp+8) %esi)
35920       e9/jump $emit-subx-call-operand:end/disp32
35921     }
35922     # else if (operand->stack-offset) emit "*(ebp+__)"
35923     {
35924       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
35925       74/jump-if-= break/disp8
35926 $emit-subx-call-operand:stack:
35927       (emit-subx-call-operand-stack *(ebp+8) %esi)
35928       e9/jump $emit-subx-call-operand:end/disp32
35929     }
35930     # else if (operand->type == literal) emit "__"
35931     {
35932       (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
35933       81 7/subop/compare *(eax+4) 0/imm32  # Type-tree-value
35934       75/jump-if-!= break/disp8
35935 $emit-subx-call-operand:literal:
35936       (write-buffered *(ebp+8) Space)
35937       (lookup *esi *(esi+4))  # Var-name Var-name => eax
35938       (write-buffered *(ebp+8) %eax)
35939       e9/jump $emit-subx-call-operand:end/disp32
35940     }
35941     # else if (operand->type == literal-string) emit "__"
35942     {
35943       (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
35944       81 7/subop/compare *(eax+4) 0x10/imm32  # Type-tree-value
35945       75/jump-if-!= break/disp8
35946 $emit-subx-call-operand:literal-string:
35947       (write-buffered *(ebp+8) Space)
35948       (lookup *esi *(esi+4))  # Var-name Var-name => eax
35949       (write-buffered *(ebp+8) %eax)
35950     }
35951 $emit-subx-call-operand:end:
35952     # . restore registers
35953     5e/pop-to-esi
35954     59/pop-to-ecx
35955     58/pop-to-eax
35956     # . epilogue
35957     89/<- %esp 5/r32/ebp
35958     5d/pop-to-ebp
35959     c3/return
35961 emit-subx-call-operand-register-indirect:  # out: (addr buffered-file), v: (addr var)
35962     # . prologue
35963     55/push-ebp
35964     89/<- %ebp 4/r32/esp
35965     # . save registers
35966     50/push-eax
35967     51/push-ecx
35968     56/push-esi
35969     # esi = v
35970     8b/-> *(ebp+0xc) 6/r32/esi
35971     # var size/ecx: int = size-of-deref(v)
35972     (size-of-deref %esi)  # => eax
35973     89/<- %ecx 0/r32/eax
35974     # var reg-name/esi: (addr array byte) = lookup(v->register)
35975     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
35976     89/<- %esi 0/r32/eax
35977     # TODO: assert size is a multiple of 4
35978     # var i/eax: int = 0
35979     b8/copy-to-eax 0/imm32
35980     {
35981 $emit-subx-call-operand-register-indirect:loop:
35982       # if (i >= size) break
35983       39/compare %eax 1/r32/ecx
35984       7d/jump-if->= break/disp8
35985       # emit " *(" v->register "+" i ")"
35986       (write-buffered *(ebp+8) " *(")
35987       (write-buffered *(ebp+8) %esi)
35988       (write-buffered *(ebp+8) "+")
35989       (write-int32-hex-buffered *(ebp+8) %eax)
35990       (write-buffered *(ebp+8) ")")
35991       # i += 4
35992       05/add-to-eax 4/imm32
35993       #
35994       eb/jump loop/disp8
35995     }
35996 $emit-subx-call-operand-register-indirect:end:
35997     # . restore registers
35998     5e/pop-to-esi
35999     59/pop-to-ecx
36000     58/pop-to-eax
36001     # . epilogue
36002     89/<- %esp 5/r32/ebp
36003     5d/pop-to-ebp
36004     c3/return
36006 emit-subx-call-operand-stack:  # out: (addr buffered-file), v: (addr var)
36007     # . prologue
36008     55/push-ebp
36009     89/<- %ebp 4/r32/esp
36010     # . save registers
36011     50/push-eax
36012     51/push-ecx
36013     56/push-esi
36014     # esi = v
36015     8b/-> *(ebp+0xc) 6/r32/esi
36016     # var curr/ecx: int = v->offset
36017     8b/-> *(esi+0x14) 1/r32/ecx  # Var-offset
36018     # var max/eax: int = v->offset + size-of(v)
36019     (size-of %esi)  # => eax
36020     # TODO: assert size is a multiple of 4
36021     01/add-to %eax 1/r32/ecx
36022     {
36023 $emit-subx-call-operand-stack:loop:
36024       # if (curr >= max) break
36025       39/compare %ecx 0/r32/eax
36026       7d/jump-if->= break/disp8
36027       # emit " *(ebp+" curr ")"
36028       (write-buffered *(ebp+8) " *(ebp+")
36029       (write-int32-hex-buffered *(ebp+8) %ecx)
36030       (write-buffered *(ebp+8) ")")
36031       # i += 4
36032       81 0/subop/add %ecx 4/imm32
36033       #
36034       eb/jump loop/disp8
36035     }
36036 $emit-subx-call-operand-stack:end:
36037     # . restore registers
36038     5e/pop-to-esi
36039     59/pop-to-ecx
36040     58/pop-to-eax
36041     # . epilogue
36042     89/<- %esp 5/r32/ebp
36043     5d/pop-to-ebp
36044     c3/return
36046 emit-subx-var-as-rm32:  # out: (addr buffered-file), s: (addr stmt-var)
36047     # . prologue
36048     55/push-ebp
36049     89/<- %ebp 4/r32/esp
36050     # . save registers
36051     50/push-eax
36052     51/push-ecx
36053     56/push-esi
36054     # ecx = s
36055     8b/-> *(ebp+0xc) 1/r32/ecx
36056     # var operand/esi: (addr var) = lookup(s->value)
36057     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
36058     89/<- %esi 0/r32/eax
36059     # if (operand->register && s->is-deref?) emit "*__"
36060     {
36061 $emit-subx-var-as-rm32:check-for-register-indirect:
36062       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
36063       74/jump-if-= break/disp8
36064       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
36065       74/jump-if-= break/disp8
36066 $emit-subx-var-as-rm32:register-indirect:
36067       (write-buffered *(ebp+8) " *")
36068       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
36069       (write-buffered *(ebp+8) %eax)
36070       e9/jump $emit-subx-var-as-rm32:end/disp32
36071     }
36072     # if (operand->register && !s->is-deref?) emit "%__"
36073     {
36074 $emit-subx-var-as-rm32:check-for-register-direct:
36075       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
36076       74/jump-if-= break/disp8
36077       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
36078       75/jump-if-!= break/disp8
36079 $emit-subx-var-as-rm32:register-direct:
36080       (write-buffered *(ebp+8) " %")
36081       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
36082       (write-buffered *(ebp+8) %eax)
36083       e9/jump $emit-subx-var-as-rm32:end/disp32
36084     }
36085     # else if (operand->stack-offset) emit "*(ebp+__)"
36086     {
36087       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
36088       74/jump-if-= break/disp8
36089 $emit-subx-var-as-rm32:stack:
36090       (write-buffered *(ebp+8) Space)
36091       (write-buffered *(ebp+8) "*(ebp+")
36092       (write-int32-hex-buffered *(ebp+8) *(esi+0x14))  # Var-offset
36093       (write-buffered *(ebp+8) ")")
36094     }
36095 $emit-subx-var-as-rm32:end:
36096     # . restore registers
36097     5e/pop-to-esi
36098     59/pop-to-ecx
36099     58/pop-to-eax
36100     # . epilogue
36101     89/<- %esp 5/r32/ebp
36102     5d/pop-to-ebp
36103     c3/return
36105 find-matching-primitive:  # primitives: (addr primitive), stmt: (addr stmt) -> result/eax: (addr primitive)
36106     # . prologue
36107     55/push-ebp
36108     89/<- %ebp 4/r32/esp
36109     # . save registers
36110     51/push-ecx
36111     # var curr/ecx: (addr primitive) = primitives
36112     8b/-> *(ebp+8) 1/r32/ecx
36113     {
36114 $find-matching-primitive:loop:
36115       # if (curr == null) break
36116       81 7/subop/compare %ecx 0/imm32
36117       74/jump-if-= break/disp8
36118       # if match(curr, stmt) return curr
36119       {
36120         (mu-stmt-matches-primitive? *(ebp+0xc) %ecx)  # => eax
36121         3d/compare-eax-and 0/imm32/false
36122         74/jump-if-= break/disp8
36123         89/<- %eax 1/r32/ecx
36124         eb/jump $find-matching-primitive:end/disp8
36125       }
36126 $find-matching-primitive:next-primitive:
36127       # curr = curr->next
36128       (lookup *(ecx+0x3c) *(ecx+0x40))  # Primitive-next Primitive-next => eax
36129       89/<- %ecx 0/r32/eax
36130       #
36131       e9/jump loop/disp32
36132     }
36133     # return null
36134     b8/copy-to-eax 0/imm32
36135 $find-matching-primitive:end:
36136     # . restore registers
36137     59/pop-to-ecx
36138     # . epilogue
36139     89/<- %esp 5/r32/ebp
36140     5d/pop-to-ebp
36141     c3/return
36143 mu-stmt-matches-primitive?:  # stmt: (addr stmt), primitive: (addr primitive) -> result/eax: boolean
36144     # A mu stmt matches a primitive if the name matches, all the inout vars
36145     # match, and all the output vars match.
36146     # Vars match if types match and registers match.
36147     # In addition, a stmt output matches a primitive's output if types match
36148     # and the primitive has a wildcard register.
36149     # . prologue
36150     55/push-ebp
36151     89/<- %ebp 4/r32/esp
36152     # . save registers
36153     51/push-ecx
36154     52/push-edx
36155     53/push-ebx
36156     56/push-esi
36157     57/push-edi
36158     # ecx = stmt
36159     8b/-> *(ebp+8) 1/r32/ecx
36160     # edx = primitive
36161     8b/-> *(ebp+0xc) 2/r32/edx
36162     {
36163 $mu-stmt-matches-primitive?:check-name:
36164       # if (primitive->name != stmt->operation) return false
36165       # . var esi: (addr array byte) = lookup(stmt->operation)
36166       (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
36167       89/<- %esi 0/r32/eax
36168       # . var edi: (addr array byte) = lookup(primitive->name)
36169       (lookup *edx *(edx+4))  # Primitive-name Primitive-name => eax
36170 #?       (write-buffered Stderr %eax)
36171 #?       (write-buffered Stderr Newline)
36172 #?       (flush Stderr)
36173       89/<- %edi 0/r32/eax
36174       (string-equal? %esi %edi)  # => eax
36175       3d/compare-eax-and 0/imm32/false
36176       75/jump-if-!= break/disp8
36177       b8/copy-to-eax 0/imm32
36178       e9/jump $mu-stmt-matches-primitive?:end/disp32
36179     }
36180     # var curr/esi: (addr stmt-var) = lookup(stmt->inouts)
36181     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
36182     89/<- %esi 0/r32/eax
36183     # var curr2/edi: (addr list var) = lookup(primitive->inouts)
36184     (lookup *(edx+8) *(edx+0xc))  # Primitive-inouts Primitive-inouts => eax
36185     89/<- %edi 0/r32/eax
36186     {
36187 $mu-stmt-matches-primitive?:inouts-loop:
36188       # if (curr == 0 && curr2 == 0) move on to check outputs
36189       {
36190 $mu-stmt-matches-primitive?:check-both-inouts-null:
36191         81 7/subop/compare %esi 0/imm32
36192         75/jump-if-!= break/disp8
36193 $mu-stmt-matches-primitive?:stmt-inout-null:
36194         81 7/subop/compare %edi 0/imm32
36195         0f 84/jump-if-= $mu-stmt-matches-primitive?:check-outputs/disp32
36196 $mu-stmt-matches-primitive?:stmt-inout-null-and-prim-inout-not-null:
36197         # return false
36198         b8/copy-to-eax 0/imm32/false
36199         e9/jump $mu-stmt-matches-primitive?:end/disp32
36200       }
36201       # if (curr2 == 0) return false
36202       {
36203 $mu-stmt-matches-primitive?:check-prim-inout-null:
36204         81 7/subop/compare %edi 0/imm32
36205         75/jump-if-!= break/disp8
36206 $mu-stmt-matches-primitive?:prim-inout-null:
36207         b8/copy-to-eax 0/imm32/false
36208         e9/jump $mu-stmt-matches-primitive?:end/disp32
36209       }
36210       # if (curr != curr2) return false
36211       {
36212 $mu-stmt-matches-primitive?:check-inouts-match:
36213         (lookup *edi *(edi+4))  # List-value List-value => eax
36214         (operand-matches-primitive? %esi %eax)  # => eax
36215         3d/compare-eax-and 0/imm32/false
36216         75/jump-if-!= break/disp8
36217 $mu-stmt-matches-primitive?:inouts-match:
36218         b8/copy-to-eax 0/imm32/false
36219         e9/jump $mu-stmt-matches-primitive?:end/disp32
36220       }
36221 $mu-stmt-matches-primitive?:next-inout:
36222       # curr = lookup(curr->next)
36223       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
36224       89/<- %esi 0/r32/eax
36225       # curr2 = lookup(curr2->next)
36226       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
36227       89/<- %edi 0/r32/eax
36228       #
36229       e9/jump loop/disp32
36230     }
36231 $mu-stmt-matches-primitive?:check-outputs:
36232     # var curr/esi: (addr stmt-var) = lookup(stmt->outputs)
36233     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
36234     89/<- %esi 0/r32/eax
36235     # var curr2/edi: (addr list var) = lookup(primitive->outputs)
36236     (lookup *(edx+0x10) *(edx+0x14))  # Primitive-outputs Primitive-outputs => eax
36237     89/<- %edi 0/r32/eax
36238     {
36239 $mu-stmt-matches-primitive?:outputs-loop:
36240       # if (curr == 0) return (curr2 == 0)
36241       {
36242 $mu-stmt-matches-primitive?:check-both-outputs-null:
36243         81 7/subop/compare %esi 0/imm32
36244         75/jump-if-!= break/disp8
36245         {
36246 $mu-stmt-matches-primitive?:stmt-output-null:
36247           81 7/subop/compare %edi 0/imm32
36248           75/jump-if-!= break/disp8
36249 $mu-stmt-matches-primitive?:both-outputs-null:
36250           # return true
36251           b8/copy-to-eax 1/imm32
36252           e9/jump $mu-stmt-matches-primitive?:end/disp32
36253         }
36254 $mu-stmt-matches-primitive?:stmt-output-null-and-prim-output-not-null:
36255         # return false
36256         b8/copy-to-eax 0/imm32
36257         e9/jump $mu-stmt-matches-primitive?:end/disp32
36258       }
36259       # if (curr2 == 0) return false
36260       {
36261 $mu-stmt-matches-primitive?:check-prim-output-null:
36262         81 7/subop/compare %edi 0/imm32
36263         75/jump-if-!= break/disp8
36264 $mu-stmt-matches-primitive?:prim-output-is-null:
36265         b8/copy-to-eax 0/imm32
36266         e9/jump $mu-stmt-matches-primitive?:end/disp32
36267       }
36268       # if (curr != curr2) return false
36269       {
36270 $mu-stmt-matches-primitive?:check-outputs-match:
36271         (lookup *edi *(edi+4))  # List-value List-value => eax
36272         (operand-matches-primitive? %esi %eax)  # => eax
36273         3d/compare-eax-and 0/imm32/false
36274         75/jump-if-!= break/disp8
36275 $mu-stmt-matches-primitive?:outputs-match:
36276         b8/copy-to-eax 0/imm32
36277         e9/jump $mu-stmt-matches-primitive?:end/disp32
36278       }
36279 $mu-stmt-matches-primitive?:next-output:
36280       # curr = lookup(curr->next)
36281       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
36282       89/<- %esi 0/r32/eax
36283       # curr2 = lookup(curr2->next)
36284       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
36285       89/<- %edi 0/r32/eax
36286       #
36287       e9/jump loop/disp32
36288     }
36289 $mu-stmt-matches-primitive?:return-true:
36290     b8/copy-to-eax 1/imm32
36291 $mu-stmt-matches-primitive?:end:
36292     # . restore registers
36293     5f/pop-to-edi
36294     5e/pop-to-esi
36295     5b/pop-to-ebx
36296     5a/pop-to-edx
36297     59/pop-to-ecx
36298     # . epilogue
36299     89/<- %esp 5/r32/ebp
36300     5d/pop-to-ebp
36301     c3/return
36303 operand-matches-primitive?:  # s: (addr stmt-var), prim-var: (addr var) -> result/eax: boolean
36304     # . prologue
36305     55/push-ebp
36306     89/<- %ebp 4/r32/esp
36307     # . save registers
36308     51/push-ecx
36309     52/push-edx
36310     53/push-ebx
36311     56/push-esi
36312     57/push-edi
36313     # ecx = s
36314     8b/-> *(ebp+8) 1/r32/ecx
36315     # var var/esi: (addr var) = lookup(s->value)
36316     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
36317     89/<- %esi 0/r32/eax
36318     # edi = prim-var
36319     8b/-> *(ebp+0xc) 7/r32/edi
36320 $operand-matches-primitive?:check-type:
36321     # if !category-match?(var->type, prim-var->type) return false
36322     # . var vtype/ebx: (addr type-tree) = lookup(var->type)
36323     (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
36324     89/<- %ebx 0/r32/eax
36325     # . if s is deref, vtype = vtype->right
36326     {
36327       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
36328       74/jump-if-= break/disp8
36329 $operand-matches-primitive?:is-deref:
36330       # . var t/eax: (addr type)
36331       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
36332       # . if !t->is-atom? t = t->left
36333       81 7/subop/compare *eax 0/imm32/false
36334       {
36335         75/jump-if-!= break/disp8
36336         (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
36337       }
36338       # .
36339       89/<- %ebx 0/r32/eax
36340     }
36341     # . var ptype/eax: (addr type-tree) = lookup(prim-var->type)
36342     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
36343     (subx-type-category-match? %ebx %eax)  # => eax
36344     3d/compare-eax-and 0/imm32/false
36345     0f 84/jump-if-= $operand-matches-primitive?:return-false/disp32
36346     {
36347 $operand-matches-primitive?:check-register:
36348       # if prim-var is in memory and var is in register but dereference, match
36349       {
36350         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
36351         0f 85/jump-if-!= break/disp32
36352         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
36353         74/jump-if-= break/disp8
36354         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
36355         74/jump-if-= break/disp8
36356 $operand-matches-primitive?:var-deref-match:
36357         e9/jump $operand-matches-primitive?:return-true/disp32
36358       }
36359       # if prim-var is in register and var is in register but dereference, no match
36360       {
36361         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
36362         0f 84/jump-if-= break/disp32
36363         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
36364         0f 84/jump-if-= break/disp32
36365         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
36366         74/jump-if-= break/disp8
36367 $operand-matches-primitive?:var-deref-no-match:
36368         e9/jump $operand-matches-primitive?:return-false/disp32
36369       }
36370       # return false if var->register doesn't match prim-var->register
36371       {
36372         # if register addresses are equal, it's a match
36373         # var vreg/ebx: (addr array byte) = lookup(var->register)
36374         (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
36375         89/<- %ebx 0/r32/eax
36376         # var preg/ecx: (addr array byte) = lookup(prim-var->register)
36377         (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
36378         89/<- %ecx 0/r32/eax
36379         # if (vreg == preg) break
36380         39/compare %ecx 3/r32/ebx
36381         74/jump-if-= break/disp8
36382 $operand-matches-primitive?:var-register-no-match:
36383         # if either address is 0, return false
36384         81 7/subop/compare %ebx 0/imm32
36385         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
36386         81 7/subop/compare %ecx 0/imm32
36387         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
36388         # if prim-var->register is wildcard, it's a match
36389         (string-equal? %ecx "*")  # Any-register => eax
36390         3d/compare-eax-and 0/imm32/false
36391         75/jump-if-!= break/disp8
36392 $operand-matches-primitive?:wildcard-no-match:
36393         # if string contents aren't equal, return false
36394         (string-equal? %ecx %ebx)  # => eax
36395         3d/compare-eax-and 0/imm32/false
36396         74/jump-if-= $operand-matches-primitive?:return-false/disp8
36397       }
36398     }
36399 $operand-matches-primitive?:return-true:
36400     b8/copy-to-eax 1/imm32/true
36401     eb/jump $operand-matches-primitive?:end/disp8
36402 $operand-matches-primitive?:return-false:
36403     b8/copy-to-eax 0/imm32/false
36404 $operand-matches-primitive?:end:
36405     # . restore registers
36406     5f/pop-to-edi
36407     5e/pop-to-esi
36408     5b/pop-to-ebx
36409     5a/pop-to-edx
36410     59/pop-to-ecx
36411     # . epilogue
36412     89/<- %esp 5/r32/ebp
36413     5d/pop-to-ebp
36414     c3/return
36416 find-matching-function:  # functions: (addr function), stmt: (addr stmt) -> result/eax: (addr function)
36417     # . prologue
36418     55/push-ebp
36419     89/<- %ebp 4/r32/esp
36420     # . save registers
36421     51/push-ecx
36422     # var curr/ecx: (handle function) = functions
36423     8b/-> *(ebp+8) 1/r32/ecx
36424     {
36425       # if (curr == null) break
36426       81 7/subop/compare %ecx 0/imm32
36427       74/jump-if-= break/disp8
36428 #?       (write-buffered Stderr "iter\n")
36429 #?       (flush Stderr)
36430       # if match(stmt, curr) return curr
36431       {
36432         (mu-stmt-matches-function? *(ebp+0xc) %ecx)  # => eax
36433         3d/compare-eax-and 0/imm32/false
36434         74/jump-if-= break/disp8
36435         89/<- %eax 1/r32/ecx
36436         eb/jump $find-matching-function:end/disp8
36437       }
36438       # curr = curr->next
36439       (lookup *(ecx+0x20) *(ecx+0x24))  # Function-next Function-next => eax
36440       89/<- %ecx 0/r32/eax
36441       #
36442       eb/jump loop/disp8
36443     }
36444     # return null
36445     b8/copy-to-eax 0/imm32
36446 $find-matching-function:end:
36447     # . restore registers
36448     59/pop-to-ecx
36449     # . epilogue
36450     89/<- %esp 5/r32/ebp
36451     5d/pop-to-ebp
36452     c3/return
36454 # Just compare names; user-defined functions don't support overloading yet.
36455 mu-stmt-matches-function?:  # stmt: (addr stmt1), function: (addr function) -> result/eax: boolean
36456     # . prologue
36457     55/push-ebp
36458     89/<- %ebp 4/r32/esp
36459     # . save registers
36460     51/push-ecx
36461     # return function->name == stmt->operation
36462     # ecx = lookup(stmt->operation)
36463     8b/-> *(ebp+8) 0/r32/eax
36464     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
36465     89/<- %ecx 0/r32/eax
36466     # eax = lookup(function->name)
36467     8b/-> *(ebp+0xc) 0/r32/eax
36468     (lookup *eax *(eax+4))  # Function-name Function-name => eax
36469     (string-equal? %eax %ecx)  # => eax
36470 $mu-stmt-matches-function?:end:
36471     # . restore registers
36472     59/pop-to-ecx
36473     # . epilogue
36474     89/<- %esp 5/r32/ebp
36475     5d/pop-to-ebp
36476     c3/return
36478 # Type-checking happens elsewhere. This method is for selecting between
36479 # primitives.
36480 subx-type-category-match?:  # a: (addr type-tree), b: (addr type-tree) -> result/eax: boolean
36481     # . prologue
36482     55/push-ebp
36483     89/<- %ebp 4/r32/esp
36484     # . save registers
36485     51/push-ecx
36486     # var cata/ecx: int = type-category(a)
36487     (type-category *(ebp+8))  # => eax
36488     89/<- %ecx 0/r32/eax
36489     # var catb/eax: int = type-category(b)
36490     (type-category *(ebp+0xc))  # => eax
36491     # return cata == catb
36492     39/compare %eax 1/r32/ecx
36493     0f 94/set-byte-if-= %al
36494     25/and-eax-with 0xff/imm32
36495 $subx-type-category-match?:end:
36496     # . restore registers
36497     59/pop-to-ecx
36498     # . epilogue
36499     89/<- %esp 5/r32/ebp
36500     5d/pop-to-ebp
36501     c3/return
36503 type-category:  # a: (addr type-tree) -> result/eax: int
36504     # . prologue
36505     55/push-ebp
36506     89/<- %ebp 4/r32/esp
36507     # . save registers
36508     51/push-ecx
36509     # var lit?/ecx: boolean = literal-type?(a)
36510     (simple-mu-type? *(ebp+8) 0)  # literal => eax
36511     89/<- %ecx 0/r32/eax
36512     # lit? |= string-literal?(a)
36513     (simple-mu-type? *(ebp+8) 0x10)  # literal-string => eax
36514     09/or %ecx 0/r32/eax
36515     # var float?/eax: int = float?(a)
36516     (simple-mu-type? *(ebp+8) 0xf)  # => eax
36517     # set bits for lit? and float?
36518     c1/shift 4/subop/left %ecx 1/imm8
36519     09/or %eax 1/r32/ecx
36520 $type-category:end:
36521     # . restore registers
36522     59/pop-to-ecx
36523     # . epilogue
36524     89/<- %esp 5/r32/ebp
36525     5d/pop-to-ebp
36526     c3/return
36528 simple-mu-type?:  # a: (addr type-tree), n: type-id -> result/eax: boolean
36529     # . prologue
36530     55/push-ebp
36531     89/<- %ebp 4/r32/esp
36532     # . save registers
36533     51/push-ecx
36534     # ecx = n
36535     8b/-> *(ebp+0xc) 1/r32/ecx
36536     # return (a->value == n)
36537     8b/-> *(ebp+8) 0/r32/eax
36538     39/compare *(eax+4) 1/r32/ecx  # Type-tree-value
36539     0f 94/set-byte-if-= %al
36540     25/and-eax-with 0xff/imm32
36541 $simple-mu-type?:end:
36542     # . restore registers
36543     59/pop-to-ecx
36544     # . epilogue
36545     89/<- %esp 5/r32/ebp
36546     5d/pop-to-ebp
36547     c3/return
36549 mu-addr-type?:  # a: (addr type-tree) -> result/eax: boolean
36550     # . prologue
36551     55/push-ebp
36552     89/<- %ebp 4/r32/esp
36553     # eax = a
36554     8b/-> *(ebp+8) 0/r32/eax
36555     # if (!a->is-atom?) a = a->left
36556     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
36557     {
36558       75/jump-if-!= break/disp8
36559       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
36560     }
36561     # return (a->value == addr)
36562     81 7/subop/compare *(eax+4) 2/imm32/addr  # Type-tree-value
36563     0f 94/set-byte-if-= %al
36564     25/and-eax-with 0xff/imm32
36565 $mu-addr-type?:end:
36566     # . epilogue
36567     89/<- %esp 5/r32/ebp
36568     5d/pop-to-ebp
36569     c3/return
36571 mu-array-type?:  # a: (addr type-tree) -> result/eax: boolean
36572     # . prologue
36573     55/push-ebp
36574     89/<- %ebp 4/r32/esp
36575     # eax = a
36576     8b/-> *(ebp+8) 0/r32/eax
36577     # if (!a->is-atom?) a = a->left
36578     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
36579     {
36580       75/jump-if-!= break/disp8
36581       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
36582     }
36583     # return (a->value == array)
36584     81 7/subop/compare *(eax+4) 3/imm32/array  # Type-tree-value
36585     0f 94/set-byte-if-= %al
36586     25/and-eax-with 0xff/imm32
36587 $mu-array-type?:end:
36588     # . epilogue
36589     89/<- %esp 5/r32/ebp
36590     5d/pop-to-ebp
36591     c3/return
36593 mu-string-type?:  # a: (addr type-tree) -> result/eax: boolean
36594     # . prologue
36595     55/push-ebp
36596     89/<- %ebp 4/r32/esp
36597     # . save registers
36598     56/push-esi
36599     # esi = a
36600     8b/-> *(ebp+8) 6/r32/esi
36601     # if (a->is-atom?) return false
36602     81 7/subop/compare *esi 0/imm32/false  # Type-tree-is-atom
36603     0f 85/jump-if-!= $mu-string-type?:return-false/disp32
36604     # if a is not an addr, return false
36605     (mu-addr-type? %esi)  # => eax
36606     3d/compare-eax-with 0/imm32/false
36607     0f 84/jump-if-= $mu-string-type?:end/disp32  # eax changes var
36608     # if a is not an array, return false
36609     (lookup *(esi+0xc) *(esi+0x10))  # Type-tree-right Type-tree-right => eax
36610     (mu-array-type? %eax)  # => eax
36611     3d/compare-eax-with 0/imm32/false
36612     74/jump-if-= $mu-string-type?:end/disp8  # eax changes var
36613     # var p/eax: (addr type-tree) = payload of a
36614     (lookup *(esi+0xc) *(esi+0x10))  # Type-tree-right Type-tree-right => eax
36615     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
36616     # if p is an atom, return false
36617     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
36618     75/jump-if-!= $mu-string-type?:return-false/disp8
36619     # return (p == byte)
36620     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
36621     (simple-mu-type? %eax 8)  # byte => eax
36622     eb/jump $mu-string-type?:end/disp8
36623 $mu-string-type?:return-false:
36624     b8/copy-to-eax 0/imm32/false
36625 $mu-string-type?:end:
36626     # . restore registers
36627     5e/pop-to-esi
36628     # . epilogue
36629     89/<- %esp 5/r32/ebp
36630     5d/pop-to-ebp
36631     c3/return
36633 mu-stream-type?:  # a: (addr type-tree) -> result/eax: boolean
36634     # . prologue
36635     55/push-ebp
36636     89/<- %ebp 4/r32/esp
36637     # eax = a
36638     8b/-> *(ebp+8) 0/r32/eax
36639     # if (!a->is-atom?) a = a->left
36640     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
36641     {
36642       75/jump-if-!= break/disp8
36643       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
36644     }
36645     # return (a->value == stream)
36646     81 7/subop/compare *(eax+4) 0xb/imm32/stream  # Type-tree-value
36647     0f 94/set-byte-if-= %al
36648     25/and-eax-with 0xff/imm32
36649 $mu-stream-type?:end:
36650     # . epilogue
36651     89/<- %esp 5/r32/ebp
36652     5d/pop-to-ebp
36653     c3/return
36655 test-emit-subx-stmt-primitive:
36656     # Primitive operation on a variable on the stack.
36657     #   increment foo
36658     # =>
36659     #   ff 0/subop/increment *(ebp-8)
36660     #
36661     # There's a variable on the var stack as follows:
36662     #   name: 'foo'
36663     #   type: int
36664     #   stack-offset: -8
36665     #
36666     # There's a primitive with this info:
36667     #   name: 'increment'
36668     #   inouts: int/mem
36669     #   value: 'ff 0/subop/increment'
36670     #
36671     # . prologue
36672     55/push-ebp
36673     89/<- %ebp 4/r32/esp
36674     # setup
36675     (clear-stream _test-output-stream)
36676     (clear-stream $_test-output-buffered-file->buffer)
36677     # simulate allocated payloads starting with an initial fake alloc-id (0x11)
36678 $test-emit-subx-stmt-primitive:initialize-type:
36679     # var type/ecx: (payload type-tree) = int
36680     68/push 0/imm32/right:null
36681     68/push 0/imm32/right:null
36682     68/push 0/imm32/left:unused
36683     68/push 1/imm32/value:int
36684     68/push 1/imm32/is-atom?:true
36685     68/push 0x11/imm32/alloc-id:fake:payload
36686     89/<- %ecx 4/r32/esp
36687 $test-emit-subx-stmt-primitive:initialize-var:
36688     # var var-foo/ecx: (payload var) = var(type)
36689     68/push 0/imm32/no-register
36690     68/push 0/imm32/no-register
36691     68/push -8/imm32/stack-offset
36692     68/push 1/imm32/block-depth
36693     51/push-ecx/type
36694     68/push 0x11/imm32/alloc-id:fake
36695     68/push 0/imm32/name
36696     68/push 0/imm32/name
36697     68/push 0x11/imm32/alloc-id:fake:payload
36698     89/<- %ecx 4/r32/esp
36699 $test-emit-subx-stmt-primitive:initialize-var-name:
36700     # var-foo->name = "foo"
36701     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
36702     (copy-array Heap "foo" %eax)
36703 $test-emit-subx-stmt-primitive:initialize-stmt-var:
36704     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
36705     68/push 0/imm32/is-deref:false
36706     68/push 0/imm32/next
36707     68/push 0/imm32/next
36708     51/push-ecx/var-foo
36709     68/push 0x11/imm32/alloc-id:fake
36710     68/push 0x11/imm32/alloc-id:fake:payload
36711     89/<- %ebx 4/r32/esp
36712 $test-emit-subx-stmt-primitive:initialize-stmt:
36713     # var stmt/esi: (addr statement)
36714     68/push 0/imm32/no-outputs
36715     68/push 0/imm32/no-outputs
36716     53/push-ebx/inouts
36717     68/push 0x11/imm32/alloc-id:fake
36718     68/push 0/imm32/operation
36719     68/push 0/imm32/operation
36720     68/push 1/imm32/tag
36721     89/<- %esi 4/r32/esp
36722 $test-emit-subx-stmt-primitive:initialize-stmt-operation:
36723     # stmt->operation = "increment"
36724     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
36725     (copy-array Heap "increment" %eax)
36726 $test-emit-subx-stmt-primitive:initialize-primitive:
36727     # var primitives/ebx: (addr primitive)
36728     68/push 0/imm32/next
36729     68/push 0/imm32/next
36730     68/push 0/imm32/no-x32
36731     68/push 0/imm32/no-xm32
36732     68/push 0/imm32/no-disp32
36733     68/push 0/imm32/no-imm8
36734     68/push 0/imm32/no-imm32
36735     68/push 0/imm32/no-r32
36736     68/push 1/imm32/rm32-is-first-inout
36737     68/push 0/imm32/subx-name
36738     68/push 0/imm32/subx-name
36739     68/push 0/imm32/no-outputs
36740     68/push 0/imm32/no-outputs
36741     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
36742     68/push 0x11/imm32/alloc-id:fake
36743     68/push 0/imm32/name
36744     68/push 0/imm32/name
36745     89/<- %ebx 4/r32/esp
36746 $test-emit-subx-stmt-primitive:initialize-primitive-name:
36747     # primitives->name = "increment"
36748     (copy-array Heap "increment" %ebx)  # Primitive-name
36749 $test-emit-subx-stmt-primitive:initialize-primitive-subx-name:
36750     # primitives->subx-name = "ff 0/subop/increment"
36751     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
36752     (copy-array Heap "ff 0/subop/increment" %eax)
36753     # convert
36754     c7 0/subop/copy *Curr-block-depth 0/imm32
36755     (emit-subx-stmt _test-output-buffered-file %esi %ebx 0 Stderr 0)
36756     (flush _test-output-buffered-file)
36757 #?     # dump _test-output-stream {{{
36758 #?     (write 2 "^")
36759 #?     (write-stream 2 _test-output-stream)
36760 #?     (write 2 "$\n")
36761 #?     (rewind-stream _test-output-stream)
36762 #?     # }}}
36763     # check output
36764     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-stmt-primitive")
36765     # . epilogue
36766     89/<- %esp 5/r32/ebp
36767     5d/pop-to-ebp
36768     c3/return
36770 test-emit-subx-stmt-primitive-register:
36771     # Primitive operation on a variable in a register.
36772     #   foo <- increment
36773     # =>
36774     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
36775     #
36776     # There's a variable on the var stack as follows:
36777     #   name: 'foo'
36778     #   type: int
36779     #   register: 'eax'
36780     #
36781     # There's a primitive with this info:
36782     #   name: 'increment'
36783     #   out: int/reg
36784     #   value: 'ff 0/subop/increment'
36785     #
36786     # . prologue
36787     55/push-ebp
36788     89/<- %ebp 4/r32/esp
36789     # setup
36790     (clear-stream _test-output-stream)
36791     (clear-stream $_test-output-buffered-file->buffer)
36792 $test-emit-subx-stmt-primitive-register:initialize-type:
36793     # var type/ecx: (payload type-tree) = int
36794     68/push 0/imm32/right:null
36795     68/push 0/imm32/right:null
36796     68/push 0/imm32/left:unused
36797     68/push 1/imm32/value:int
36798     68/push 1/imm32/is-atom?:true
36799     68/push 0x11/imm32/alloc-id:fake:payload
36800     89/<- %ecx 4/r32/esp
36801 $test-emit-subx-stmt-primitive-register:initialize-var:
36802     # var var-foo/ecx: (payload var)
36803     68/push 0/imm32/register
36804     68/push 0/imm32/register
36805     68/push 0/imm32/no-stack-offset
36806     68/push 1/imm32/block-depth
36807     51/push-ecx
36808     68/push 0x11/imm32/alloc-id:fake
36809     68/push 0/imm32/name
36810     68/push 0/imm32/name
36811     68/push 0x11/imm32/alloc-id:fake:payload
36812     89/<- %ecx 4/r32/esp
36813 $test-emit-subx-stmt-primitive-register:initialize-var-name:
36814     # var-foo->name = "foo"
36815     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
36816     (copy-array Heap "foo" %eax)
36817 $test-emit-subx-stmt-primitive-register:initialize-var-register:
36818     # var-foo->register = "eax"
36819     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
36820     (copy-array Heap "eax" %eax)
36821 $test-emit-subx-stmt-primitive-register:initialize-stmt-var:
36822     # var operand/ebx: (payload stmt-var)
36823     68/push 0/imm32/is-deref:false
36824     68/push 0/imm32/next
36825     68/push 0/imm32/next
36826     51/push-ecx/var-foo
36827     68/push 0x11/imm32/alloc-id:fake
36828     68/push 0x11/imm32/alloc-id:fake:payload
36829     89/<- %ebx 4/r32/esp
36830 $test-emit-subx-stmt-primitive-register:initialize-stmt:
36831     # var stmt/esi: (addr statement)
36832     53/push-ebx/outputs
36833     68/push 0x11/imm32/alloc-id:fake
36834     68/push 0/imm32/no-inouts
36835     68/push 0/imm32/no-inouts
36836     68/push 0/imm32/operation
36837     68/push 0/imm32/operation
36838     68/push 1/imm32
36839     89/<- %esi 4/r32/esp
36840 $test-emit-subx-stmt-primitive-register:initialize-stmt-operation:
36841     # stmt->operation = "increment"
36842     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
36843     (copy-array Heap "increment" %eax)
36844 $test-emit-subx-stmt-primitive-register:initialize-formal-var:
36845     # var formal-var/ebx: (payload var)
36846     68/push 0/imm32/register
36847     68/push 0/imm32/register
36848     68/push 0/imm32/no-stack-offset
36849     68/push 1/imm32/block-depth
36850     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
36851     68/push 0x11/imm32/alloc-id:fake
36852     68/push 0/imm32/name
36853     68/push 0/imm32/name
36854     68/push 0x11/imm32/alloc-id:fake:payload
36855     89/<- %ebx 4/r32/esp
36856 $test-emit-subx-stmt-primitive-register:initialize-formal-var-name:
36857     # formal-var->name = "dummy"
36858     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
36859     (copy-array Heap "dummy" %eax)
36860 $test-emit-subx-stmt-primitive-register:initialize-formal-register:
36861     # formal-var->register = "*"
36862     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
36863     (copy-array Heap "*" %eax)  # Any-register
36864 $test-emit-subx-stmt-primitive-register:initialize-var-list:
36865     # var formal-outputs/ebx: (payload list var)
36866     68/push 0/imm32/next
36867     68/push 0/imm32/next
36868     53/push-ebx/formal-var
36869     68/push 0x11/imm32/alloc-id:fake
36870     68/push 0x11/imm32/alloc-id:fake:payload
36871     89/<- %ebx 4/r32/esp
36872 $test-emit-subx-stmt-primitive-register:initialize-primitive:
36873     # var primitives/ebx: (addr primitive)
36874     68/push 0/imm32/next
36875     68/push 0/imm32/next
36876     68/push 0/imm32/no-x32
36877     68/push 0/imm32/no-xm32
36878     68/push 0/imm32/no-disp32
36879     68/push 0/imm32/no-imm8
36880     68/push 0/imm32/no-imm32
36881     68/push 0/imm32/no-r32
36882     68/push 3/imm32/rm32-is-first-output
36883     68/push 0/imm32/subx-name
36884     68/push 0/imm32/subx-name
36885     53/push-ebx/outputs
36886     68/push 0x11/imm32/alloc-id:fake
36887     68/push 0/imm32/no-inouts
36888     68/push 0/imm32/no-inouts
36889     68/push 0/imm32/name
36890     68/push 0/imm32/name
36891     89/<- %ebx 4/r32/esp
36892 $test-emit-subx-stmt-primitive-register:initialize-primitive-name:
36893     # primitives->name = "increment"
36894     (copy-array Heap "increment" %ebx)  # Primitive-name
36895 $test-emit-subx-stmt-primitive-register:initialize-primitive-subx-name:
36896     # primitives->subx-name = "ff 0/subop/increment"
36897     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
36898     (copy-array Heap "ff 0/subop/increment" %eax)
36899     # convert
36900     c7 0/subop/copy *Curr-block-depth 0/imm32
36901     (emit-subx-stmt _test-output-buffered-file %esi %ebx 0 Stderr 0)
36902     (flush _test-output-buffered-file)
36903 #?     # dump _test-output-stream {{{
36904 #?     (write 2 "^")
36905 #?     (write-stream 2 _test-output-stream)
36906 #?     (write 2 "$\n")
36907 #?     (rewind-stream _test-output-stream)
36908 #?     # }}}
36909     # check output
36910     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-primitive-register")
36911     # . epilogue
36912     89/<- %esp 5/r32/ebp
36913     5d/pop-to-ebp
36914     c3/return
36916 test-emit-subx-stmt-select-primitive:
36917     # Select the right primitive between overloads.
36918     #   foo <- increment
36919     # =>
36920     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
36921     #
36922     # There's a variable on the var stack as follows:
36923     #   name: 'foo'
36924     #   type: int
36925     #   register: 'eax'
36926     #
36927     # There's two primitives, as follows:
36928     #   - name: 'increment'
36929     #     out: int/reg
36930     #     value: 'ff 0/subop/increment'
36931     #   - name: 'increment'
36932     #     inout: int/mem
36933     #     value: 'ff 0/subop/increment'
36934     #
36935     # . prologue
36936     55/push-ebp
36937     89/<- %ebp 4/r32/esp
36938     # setup
36939     (clear-stream _test-output-stream)
36940     (clear-stream $_test-output-buffered-file->buffer)
36941 $test-emit-subx-stmt-select-primitive:initialize-type:
36942     # var type/ecx: (payload type-tree) = int
36943     68/push 0/imm32/right:null
36944     68/push 0/imm32/right:null
36945     68/push 0/imm32/left:unused
36946     68/push 1/imm32/value:int
36947     68/push 1/imm32/is-atom?:true
36948     68/push 0x11/imm32/alloc-id:fake:payload
36949     89/<- %ecx 4/r32/esp
36950 $test-emit-subx-stmt-select-primitive:initialize-var:
36951     # var var-foo/ecx: (payload var)
36952     68/push 0/imm32/register
36953     68/push 0/imm32/register
36954     68/push 0/imm32/no-stack-offset
36955     68/push 1/imm32/block-depth
36956     51/push-ecx
36957     68/push 0x11/imm32/alloc-id:fake
36958     68/push 0/imm32/name
36959     68/push 0/imm32/name
36960     68/push 0x11/imm32/alloc-id:fake:payload
36961     89/<- %ecx 4/r32/esp
36962 $test-emit-subx-stmt-select-primitive:initialize-var-name:
36963     # var-foo->name = "foo"
36964     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
36965     (copy-array Heap "foo" %eax)
36966 $test-emit-subx-stmt-select-primitive:initialize-var-register:
36967     # var-foo->register = "eax"
36968     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
36969     (copy-array Heap "eax" %eax)
36970 $test-emit-subx-stmt-select-primitive:initialize-stmt-var:
36971     # var operand/ebx: (payload stmt-var)
36972     68/push 0/imm32/is-deref:false
36973     68/push 0/imm32/next
36974     68/push 0/imm32/next
36975     51/push-ecx/var-foo
36976     68/push 0x11/imm32/alloc-id:fake
36977     68/push 0x11/imm32/alloc-id:fake:payload
36978     89/<- %ebx 4/r32/esp
36979 $test-emit-subx-stmt-select-primitive:initialize-stmt:
36980     # var stmt/esi: (addr statement)
36981     53/push-ebx/outputs
36982     68/push 0x11/imm32/alloc-id:fake
36983     68/push 0/imm32/no-inouts
36984     68/push 0/imm32/no-inouts
36985     68/push 0/imm32/operation
36986     68/push 0/imm32/operation
36987     68/push 1/imm32
36988     89/<- %esi 4/r32/esp
36989 $test-emit-subx-stmt-select-primitive:initialize-stmt-operation:
36990     # stmt->operation = "increment"
36991     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
36992     (copy-array Heap "increment" %eax)
36993 $test-emit-subx-stmt-select-primitive:initialize-formal-var:
36994     # var formal-var/ebx: (payload var)
36995     68/push 0/imm32/register
36996     68/push 0/imm32/register
36997     68/push 0/imm32/no-stack-offset
36998     68/push 1/imm32/block-depth
36999     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
37000     68/push 0x11/imm32/alloc-id:fake
37001     68/push 0/imm32/name
37002     68/push 0/imm32/name
37003     68/push 0x11/imm32/alloc-id:fake:payload
37004     89/<- %ebx 4/r32/esp
37005 $test-emit-subx-stmt-select-primitive:initialize-formal-var-name:
37006     # formal-var->name = "dummy"
37007     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
37008     (copy-array Heap "dummy" %eax)
37009 $test-emit-subx-stmt-select-primitive:initialize-formal-register:
37010     # formal-var->register = "*"
37011     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
37012     (copy-array Heap "*" %eax)  # Any-register
37013 $test-emit-subx-stmt-select-primitive:initialize-var-list:
37014     # var formal-outputs/ebx: (payload list var)
37015     68/push 0/imm32/next
37016     68/push 0/imm32/next
37017     53/push-ebx/formal-var
37018     68/push 0x11/imm32/alloc-id:fake
37019     68/push 0x11/imm32/alloc-id:fake:payload
37020     89/<- %ebx 4/r32/esp
37021 $test-emit-subx-stmt-select-primitive:initialize-primitive2:
37022     # var primitive2/edi: (payload primitive)
37023     68/push 0/imm32/next
37024     68/push 0/imm32/next
37025     68/push 0/imm32/no-x32
37026     68/push 0/imm32/no-xm32
37027     68/push 0/imm32/no-disp32
37028     68/push 0/imm32/no-imm8
37029     68/push 0/imm32/no-imm32
37030     68/push 0/imm32/no-r32
37031     68/push 3/imm32/rm32-is-first-output
37032     68/push 0/imm32/subx-name
37033     68/push 0/imm32/subx-name
37034     53/push-ebx/outputs
37035     68/push 0x11/imm32/alloc-id:fake
37036     68/push 0/imm32/no-inouts
37037     68/push 0/imm32/no-inouts
37038     68/push 0/imm32/name
37039     68/push 0/imm32/name
37040     68/push 0x11/imm32/alloc-id:fake:payload
37041     89/<- %edi 4/r32/esp
37042 $test-emit-subx-stmt-select-primitive:initialize-primitive2-name:
37043     # primitives->name = "increment"
37044     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
37045     (copy-array Heap "increment" %eax)
37046 $test-emit-subx-stmt-select-primitive:initialize-primitive2-subx-name:
37047     # primitives->subx-name = "ff 0/subop/increment"
37048     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
37049     (copy-array Heap "ff 0/subop/increment" %eax)
37050 $test-emit-subx-stmt-select-primitive:initialize-primitive:
37051     # var primitives/ebx: (addr primitive)
37052     57/push-edi
37053     68/push 0x11/imm32/alloc-id:fake
37054     68/push 0/imm32/no-x32
37055     68/push 0/imm32/no-xm32
37056     68/push 0/imm32/no-disp32
37057     68/push 0/imm32/no-imm8
37058     68/push 0/imm32/no-imm32
37059     68/push 0/imm32/no-r32
37060     68/push 1/imm32/rm32-is-first-inout
37061     68/push 0/imm32/subx-name
37062     68/push 0/imm32/subx-name
37063     68/push 0/imm32/no-outputs
37064     68/push 0/imm32/no-outputs
37065     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
37066     68/push 0x11/imm32/alloc-id:fake
37067     68/push 0/imm32/name
37068     68/push 0/imm32/name
37069     89/<- %ebx 4/r32/esp
37070 $test-emit-subx-stmt-select-primitive:initialize-primitive-name:
37071     # primitives->name = "increment"
37072     (copy-array Heap "increment" %ebx)  # Primitive-name
37073 $test-emit-subx-stmt-select-primitive:initialize-primitive-subx-name:
37074     # primitives->subx-name = "ff 0/subop/increment"
37075     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
37076     (copy-array Heap "ff 0/subop/increment" %eax)
37077     # convert
37078     c7 0/subop/copy *Curr-block-depth 0/imm32
37079     (emit-subx-stmt _test-output-buffered-file %esi %ebx 0 Stderr 0)
37080     (flush _test-output-buffered-file)
37081 #?     # dump _test-output-stream {{{
37082 #?     (write 2 "^")
37083 #?     (write-stream 2 _test-output-stream)
37084 #?     (write 2 "$\n")
37085 #?     (rewind-stream _test-output-stream)
37086 #?     # }}}
37087     # check output
37088     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive")
37089     # . epilogue
37090     89/<- %esp 5/r32/ebp
37091     5d/pop-to-ebp
37092     c3/return
37094 test-emit-subx-stmt-select-primitive-2:
37095     # Select the right primitive between overloads.
37096     #   increment foo
37097     # =>
37098     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
37099     #
37100     # There's a variable on the var stack as follows:
37101     #   name: 'foo'
37102     #   type: int
37103     #   register: 'eax'
37104     #
37105     # There's two primitives, as follows:
37106     #   - name: 'increment'
37107     #     out: int/reg
37108     #     value: 'ff 0/subop/increment'
37109     #   - name: 'increment'
37110     #     inout: int/mem
37111     #     value: 'ff 0/subop/increment'
37112     #
37113     # . prologue
37114     55/push-ebp
37115     89/<- %ebp 4/r32/esp
37116     # setup
37117     (clear-stream _test-output-stream)
37118     (clear-stream $_test-output-buffered-file->buffer)
37119 $test-emit-subx-stmt-select-primitive-2:initialize-type:
37120     # var type/ecx: (payload type-tree) = int
37121     68/push 0/imm32/right:null
37122     68/push 0/imm32/right:null
37123     68/push 0/imm32/left:unused
37124     68/push 1/imm32/value:int
37125     68/push 1/imm32/is-atom?:true
37126     68/push 0x11/imm32/alloc-id:fake:payload
37127     89/<- %ecx 4/r32/esp
37128 $test-emit-subx-stmt-select-primitive-2:initialize-var:
37129     # var var-foo/ecx: (payload var)
37130     68/push 0/imm32/register
37131     68/push 0/imm32/register
37132     68/push 0/imm32/no-stack-offset
37133     68/push 1/imm32/block-depth
37134     51/push-ecx
37135     68/push 0x11/imm32/alloc-id:fake
37136     68/push 0/imm32/name
37137     68/push 0/imm32/name
37138     68/push 0x11/imm32/alloc-id:fake:payload
37139     89/<- %ecx 4/r32/esp
37140 $test-emit-subx-stmt-select-primitive-2:initialize-var-name:
37141     # var-foo->name = "foo"
37142     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
37143     (copy-array Heap "foo" %eax)
37144 $test-emit-subx-stmt-select-primitive-2:initialize-var-register:
37145     # var-foo->register = "eax"
37146     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
37147     (copy-array Heap "eax" %eax)
37148 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-var:
37149     # var operand/ebx: (payload stmt-var)
37150     68/push 0/imm32/is-deref:false
37151     68/push 0/imm32/next
37152     68/push 0/imm32/next
37153     51/push-ecx/var-foo
37154     68/push 0x11/imm32/alloc-id:fake
37155     68/push 0x11/imm32/alloc-id:fake:payload
37156     89/<- %ebx 4/r32/esp
37157 $test-emit-subx-stmt-select-primitive-2:initialize-stmt:
37158     # var stmt/esi: (addr statement)
37159     68/push 0/imm32/no-outputs
37160     68/push 0/imm32/no-outputs
37161     53/push-ebx/inouts
37162     68/push 0x11/imm32/alloc-id:fake
37163     68/push 0/imm32/operation
37164     68/push 0/imm32/operation
37165     68/push 1/imm32
37166     89/<- %esi 4/r32/esp
37167 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-operation:
37168     # stmt->operation = "increment"
37169     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
37170     (copy-array Heap "increment" %eax)
37171 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var:
37172     # var formal-var/ebx: (payload var)
37173     68/push 0/imm32/register
37174     68/push 0/imm32/register
37175     68/push 0/imm32/no-stack-offset
37176     68/push 1/imm32/block-depth
37177     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
37178     68/push 0x11/imm32/alloc-id:fake
37179     68/push 0/imm32/name
37180     68/push 0/imm32/name
37181     68/push 0x11/imm32/alloc-id:fake:payload
37182     89/<- %ebx 4/r32/esp
37183 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var-name:
37184     # formal-var->name = "dummy"
37185     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
37186     (copy-array Heap "dummy" %eax)
37187 $test-emit-subx-stmt-select-primitive-2:initialize-formal-register:
37188     # formal-var->register = "*"
37189     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
37190     (copy-array Heap "*" %eax)  # Any-register
37191 $test-emit-subx-stmt-select-primitive-2:initialize-var-list:
37192     # var formal-outputs/ebx: (payload list stmt-var)
37193     68/push 0/imm32/next
37194     68/push 0/imm32/next
37195     53/push-ebx/formal-var
37196     68/push 0x11/imm32/alloc-id:fake
37197     68/push 0x11/imm32/alloc-id:fake:payload
37198     89/<- %ebx 4/r32/esp
37199 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2:
37200     # var primitive2/edi: (payload primitive)
37201     68/push 0/imm32/next
37202     68/push 0/imm32/next
37203     68/push 0/imm32/no-x32
37204     68/push 0/imm32/no-xm32
37205     68/push 0/imm32/no-disp32
37206     68/push 0/imm32/no-imm8
37207     68/push 0/imm32/no-imm32
37208     68/push 0/imm32/no-r32
37209     68/push 3/imm32/rm32-is-first-output
37210     68/push 0/imm32/subx-name
37211     68/push 0/imm32/subx-name
37212     53/push-ebx/outputs
37213     68/push 0x11/imm32/alloc-id:fake
37214     68/push 0/imm32/no-inouts
37215     68/push 0/imm32/no-inouts
37216     68/push 0/imm32/name
37217     68/push 0/imm32/name
37218     68/push 0x11/imm32/alloc-id:fake:payload
37219     89/<- %edi 4/r32/esp
37220 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-name:
37221     # primitives->name = "increment"
37222     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
37223     (copy-array Heap "increment" %eax)
37224 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-subx-name:
37225     # primitives->subx-name = "ff 0/subop/increment"
37226     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
37227     (copy-array Heap "ff 0/subop/increment" %eax)
37228 $test-emit-subx-stmt-select-primitive-2:initialize-primitive:
37229     # var primitives/ebx: (addr primitive)
37230     57/push-edi
37231     68/push 0x11/imm32/alloc-id:fake
37232     68/push 0/imm32/no-x32
37233     68/push 0/imm32/no-xm32
37234     68/push 0/imm32/no-disp32
37235     68/push 0/imm32/no-imm8
37236     68/push 0/imm32/no-imm32
37237     68/push 0/imm32/no-r32
37238     68/push 1/imm32/rm32-is-first-inout
37239     68/push 0/imm32/subx-name
37240     68/push 0/imm32/subx-name
37241     68/push 0/imm32/no-outputs
37242     68/push 0/imm32/no-outputs
37243     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
37244     68/push 0x11/imm32/alloc-id:fake
37245     68/push 0/imm32/name
37246     68/push 0/imm32/name
37247     89/<- %ebx 4/r32/esp
37248 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-name:
37249     # primitives->name = "increment"
37250     (copy-array Heap "increment" %ebx)  # Primitive-name
37251 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-subx-name:
37252     # primitives->subx-name = "ff 0/subop/increment"
37253     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
37254     (copy-array Heap "ff 0/subop/increment" %eax)
37255     # convert
37256     c7 0/subop/copy *Curr-block-depth 0/imm32
37257     (emit-subx-stmt _test-output-buffered-file %esi %ebx 0 Stderr 0)
37258     (flush _test-output-buffered-file)
37259 #?     # dump _test-output-stream {{{
37260 #?     (write 2 "^")
37261 #?     (write-stream 2 _test-output-stream)
37262 #?     (write 2 "$\n")
37263 #?     (rewind-stream _test-output-stream)
37264 #?     # }}}
37265     # check output
37266     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive-2")
37267     # . epilogue
37268     89/<- %esp 5/r32/ebp
37269     5d/pop-to-ebp
37270     c3/return
37272 test-increment-register:
37273     # Select the right register between overloads.
37274     #   foo <- increment
37275     # =>
37276     #   50/increment-eax
37277     #
37278     # There's a variable on the var stack as follows:
37279     #   name: 'foo'
37280     #   type: int
37281     #   register: 'eax'
37282     #
37283     # Primitives are the global definitions.
37284     #
37285     # . prologue
37286     55/push-ebp
37287     89/<- %ebp 4/r32/esp
37288     # setup
37289     (clear-stream _test-output-stream)
37290     (clear-stream $_test-output-buffered-file->buffer)
37291 $test-increment-register:initialize-type:
37292     # var type/ecx: (payload type-tree) = int
37293     68/push 0/imm32/right:null
37294     68/push 0/imm32/right:null
37295     68/push 0/imm32/left:unused
37296     68/push 1/imm32/value:int
37297     68/push 1/imm32/is-atom?:true
37298     68/push 0x11/imm32/alloc-id:fake:payload
37299     89/<- %ecx 4/r32/esp
37300 $test-increment-register:initialize-var:
37301     # var var-foo/ecx: (payload var)
37302     68/push 0/imm32/register
37303     68/push 0/imm32/register
37304     68/push 0/imm32/no-stack-offset
37305     68/push 1/imm32/block-depth
37306     51/push-ecx
37307     68/push 0x11/imm32/alloc-id:fake
37308     68/push 0/imm32/name
37309     68/push 0/imm32/name
37310     68/push 0x11/imm32/alloc-id:fake:payload
37311     89/<- %ecx 4/r32/esp
37312 $test-increment-register:initialize-var-name:
37313     # var-foo->name = "foo"
37314     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
37315     (copy-array Heap "foo" %eax)
37316 $test-increment-register:initialize-var-register:
37317     # var-foo->register = "eax"
37318     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
37319     (copy-array Heap "eax" %eax)
37320 $test-increment-register:initialize-stmt-var:
37321     # var operand/ebx: (payload stmt-var)
37322     68/push 0/imm32/is-deref:false
37323     68/push 0/imm32/next
37324     68/push 0/imm32/next
37325     51/push-ecx/var-foo
37326     68/push 0x11/imm32/alloc-id:fake
37327     68/push 0x11/imm32/alloc-id:fake:payload
37328     89/<- %ebx 4/r32/esp
37329 $test-increment-register:initialize-stmt:
37330     # var stmt/esi: (addr statement)
37331     53/push-ebx/outputs
37332     68/push 0x11/imm32/alloc-id:fake
37333     68/push 0/imm32/no-inouts
37334     68/push 0/imm32/no-inouts
37335     68/push 0/imm32/operation
37336     68/push 0/imm32/operation
37337     68/push 1/imm32
37338     89/<- %esi 4/r32/esp
37339 $test-increment-register:initialize-stmt-operation:
37340     # stmt->operation = "increment"
37341     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
37342     (copy-array Heap "increment" %eax)
37343     # convert
37344     c7 0/subop/copy *Curr-block-depth 0/imm32
37345     (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0)
37346     (flush _test-output-buffered-file)
37347 #?     # dump _test-output-stream {{{
37348 #?     (write 2 "^")
37349 #?     (write-stream 2 _test-output-stream)
37350 #?     (write 2 "$\n")
37351 #?     (rewind-stream _test-output-stream)
37352 #?     # }}}
37353     # check output
37354     (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register")
37355     # . epilogue
37356     89/<- %esp 5/r32/ebp
37357     5d/pop-to-ebp
37358     c3/return
37360 test-add-reg-to-reg:
37361     #   var1/reg <- add var2/reg
37362     # =>
37363     #   01/add-to %var1 var2
37364     #
37365     # . prologue
37366     55/push-ebp
37367     89/<- %ebp 4/r32/esp
37368     # setup
37369     (clear-stream _test-output-stream)
37370     (clear-stream $_test-output-buffered-file->buffer)
37371 $test-add-reg-to-reg:initialize-type:
37372     # var type/ecx: (payload type-tree) = int
37373     68/push 0/imm32/right:null
37374     68/push 0/imm32/right:null
37375     68/push 0/imm32/left:unused
37376     68/push 1/imm32/value:int
37377     68/push 1/imm32/is-atom?:true
37378     68/push 0x11/imm32/alloc-id:fake:payload
37379     89/<- %ecx 4/r32/esp
37380 $test-add-reg-to-reg:initialize-var1:
37381     # var var1/ecx: (payload var)
37382     68/push 0/imm32/register
37383     68/push 0/imm32/register
37384     68/push 0/imm32/no-stack-offset
37385     68/push 1/imm32/block-depth
37386     51/push-ecx
37387     68/push 0x11/imm32/alloc-id:fake
37388     68/push 0/imm32/name
37389     68/push 0/imm32/name
37390     68/push 0x11/imm32/alloc-id:fake:payload
37391     89/<- %ecx 4/r32/esp
37392 $test-add-reg-to-reg:initialize-var1-name:
37393     # var1->name = "var1"
37394     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
37395     (copy-array Heap "var1" %eax)
37396 $test-add-reg-to-reg:initialize-var1-register:
37397     # var1->register = "eax"
37398     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
37399     (copy-array Heap "eax" %eax)
37400 $test-add-reg-to-reg:initialize-var2:
37401     # var var2/edx: (payload var)
37402     68/push 0/imm32/register
37403     68/push 0/imm32/register
37404     68/push 0/imm32/no-stack-offset
37405     68/push 1/imm32/block-depth
37406     ff 6/subop/push *(ecx+0x10)
37407     68/push 0x11/imm32/alloc-id:fake
37408     68/push 0/imm32/name
37409     68/push 0/imm32/name
37410     68/push 0x11/imm32/alloc-id:fake:payload
37411     89/<- %edx 4/r32/esp
37412 $test-add-reg-to-reg:initialize-var2-name:
37413     # var2->name = "var2"
37414     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
37415     (copy-array Heap "var2" %eax)
37416 $test-add-reg-to-reg:initialize-var2-register:
37417     # var2->register = "ecx"
37418     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
37419     (copy-array Heap "ecx" %eax)
37420 $test-add-reg-to-reg:initialize-inouts:
37421     # var inouts/esi: (payload stmt-var) = [var2]
37422     68/push 0/imm32/is-deref:false
37423     68/push 0/imm32/next
37424     68/push 0/imm32/next
37425     52/push-edx/var2
37426     68/push 0x11/imm32/alloc-id:fake
37427     68/push 0x11/imm32/alloc-id:fake:payload
37428     89/<- %esi 4/r32/esp
37429 $test-add-reg-to-reg:initialize-outputs:
37430     # var outputs/edi: (payload stmt-var) = [var1]
37431     68/push 0/imm32/is-deref:false
37432     68/push 0/imm32/next
37433     68/push 0/imm32/next
37434     51/push-ecx/var1
37435     68/push 0x11/imm32/alloc-id:fake
37436     68/push 0x11/imm32/alloc-id:fake:payload
37437     89/<- %edi 4/r32/esp
37438 $test-add-reg-to-reg:initialize-stmt:
37439     # var stmt/esi: (addr statement)
37440     68/push 0/imm32/next
37441     68/push 0/imm32/next
37442     57/push-edi/outputs
37443     68/push 0x11/imm32/alloc-id:fake
37444     56/push-esi/inouts
37445     68/push 0x11/imm32/alloc-id:fake
37446     68/push 0/imm32/operation
37447     68/push 0/imm32/operation
37448     68/push 1/imm32/tag:stmt1
37449     89/<- %esi 4/r32/esp
37450 $test-add-reg-to-reg:initialize-stmt-operation:
37451     # stmt->operation = "add"
37452     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
37453     (copy-array Heap "add" %eax)
37454     # convert
37455     c7 0/subop/copy *Curr-block-depth 0/imm32
37456     (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0)
37457     (flush _test-output-buffered-file)
37458 #?     # dump _test-output-stream {{{
37459 #?     (write 2 "^")
37460 #?     (write-stream 2 _test-output-stream)
37461 #?     (write 2 "$\n")
37462 #?     (rewind-stream _test-output-stream)
37463 #?     # }}}
37464     # check output
37465     (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg")
37466     # . epilogue
37467     89/<- %esp 5/r32/ebp
37468     5d/pop-to-ebp
37469     c3/return
37471 test-add-reg-to-mem:
37472     #   add-to var1 var2/reg
37473     # =>
37474     #   01/add-to *(ebp+__) var2
37475     #
37476     # . prologue
37477     55/push-ebp
37478     89/<- %ebp 4/r32/esp
37479     # setup
37480     (clear-stream _test-output-stream)
37481     (clear-stream $_test-output-buffered-file->buffer)
37482 $test-add-reg-to-mem:initialize-type:
37483     # var type/ecx: (payload type-tree) = int
37484     68/push 0/imm32/right:null
37485     68/push 0/imm32/right:null
37486     68/push 0/imm32/left:unused
37487     68/push 1/imm32/value:int
37488     68/push 1/imm32/is-atom?:true
37489     68/push 0x11/imm32/alloc-id:fake:payload
37490     89/<- %ecx 4/r32/esp
37491 $test-add-reg-to-mem:initialize-var1:
37492     # var var1/ecx: (payload var)
37493     68/push 0/imm32/register
37494     68/push 0/imm32/register
37495     68/push 8/imm32/stack-offset
37496     68/push 1/imm32/block-depth
37497     51/push-ecx
37498     68/push 0x11/imm32/alloc-id:fake
37499     68/push 0/imm32/name
37500     68/push 0/imm32/name
37501     68/push 0x11/imm32/alloc-id:fake:payload
37502     89/<- %ecx 4/r32/esp
37503 $test-add-reg-to-mem:initialize-var1-name:
37504     # var1->name = "var1"
37505     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
37506     (copy-array Heap "var1" %eax)
37507 $test-add-reg-to-mem:initialize-var2:
37508     # var var2/edx: (payload var)
37509     68/push 0/imm32/register
37510     68/push 0/imm32/register
37511     68/push 0/imm32/no-stack-offset
37512     68/push 1/imm32/block-depth
37513     ff 6/subop/push *(ecx+0x10)
37514     68/push 0x11/imm32/alloc-id:fake
37515     68/push 0/imm32/name
37516     68/push 0/imm32/name
37517     68/push 0x11/imm32/alloc-id:fake:payload
37518     89/<- %edx 4/r32/esp
37519 $test-add-reg-to-mem:initialize-var2-name:
37520     # var2->name = "var2"
37521     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
37522     (copy-array Heap "var2" %eax)
37523 $test-add-reg-to-mem:initialize-var2-register:
37524     # var2->register = "ecx"
37525     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
37526     (copy-array Heap "ecx" %eax)
37527 $test-add-reg-to-mem:initialize-inouts:
37528     # var inouts/esi: (payload stmt-var) = [var2]
37529     68/push 0/imm32/is-deref:false
37530     68/push 0/imm32/next
37531     68/push 0/imm32/next
37532     52/push-edx/var2
37533     68/push 0x11/imm32/alloc-id:fake
37534     68/push 0x11/imm32/alloc-id:fake:payload
37535     89/<- %esi 4/r32/esp
37536     # inouts = [var1, var2]
37537     68/push 0/imm32/is-deref:false
37538     56/push-esi/next
37539     68/push 0x11/imm32/alloc-id:fake
37540     51/push-ecx/var1
37541     68/push 0x11/imm32/alloc-id:fake
37542     68/push 0x11/imm32/alloc-id:fake:payload
37543     89/<- %esi 4/r32/esp
37544 $test-add-reg-to-mem:initialize-stmt:
37545     # var stmt/esi: (addr statement)
37546     68/push 0/imm32/next
37547     68/push 0/imm32/next
37548     68/push 0/imm32/outputs
37549     68/push 0/imm32/outputs
37550     56/push-esi/inouts
37551     68/push 0x11/imm32/alloc-id:fake
37552     68/push 0/imm32/operation
37553     68/push 0/imm32/operation
37554     68/push 1/imm32/tag:stmt1
37555     89/<- %esi 4/r32/esp
37556 $test-add-reg-to-mem:initialize-stmt-operation:
37557     # stmt->operation = "add-to"
37558     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
37559     (copy-array Heap "add-to" %eax)
37560     # convert
37561     c7 0/subop/copy *Curr-block-depth 0/imm32
37562     (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0)
37563     (flush _test-output-buffered-file)
37564 #?     # dump _test-output-stream {{{
37565 #?     (write 2 "^")
37566 #?     (write-stream 2 _test-output-stream)
37567 #?     (write 2 "$\n")
37568 #?     (rewind-stream _test-output-stream)
37569 #?     # }}}
37570     # check output
37571     (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem")
37572     # . epilogue
37573     89/<- %esp 5/r32/ebp
37574     5d/pop-to-ebp
37575     c3/return
37577 test-add-mem-to-reg:
37578     #   var1/reg <- add var2
37579     # =>
37580     #   03/add *(ebp+__) var1
37581     #
37582     # . prologue
37583     55/push-ebp
37584     89/<- %ebp 4/r32/esp
37585     # setup
37586     (clear-stream _test-output-stream)
37587     (clear-stream $_test-output-buffered-file->buffer)
37588 $test-add-mem-to-reg:initialize-type:
37589     # var type/ecx: (payload type-tree) = int
37590     68/push 0/imm32/right:null
37591     68/push 0/imm32/right:null
37592     68/push 0/imm32/left:unused
37593     68/push 1/imm32/value:int
37594     68/push 1/imm32/is-atom?:true
37595     68/push 0x11/imm32/alloc-id:fake:payload
37596     89/<- %ecx 4/r32/esp
37597 $test-add-mem-to-reg:initialize-var:
37598     # var var1/ecx: (payload var)
37599     68/push 0/imm32/register
37600     68/push 0/imm32/register
37601     68/push 0/imm32/no-stack-offset
37602     68/push 1/imm32/block-depth
37603     51/push-ecx
37604     68/push 0x11/imm32/alloc-id:fake
37605     68/push 0/imm32/name
37606     68/push 0/imm32/name
37607     68/push 0x11/imm32/alloc-id:fake:payload
37608     89/<- %ecx 4/r32/esp
37609 $test-add-mem-to-reg:initialize-var-name:
37610     # var1->name = "foo"
37611     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
37612     (copy-array Heap "var1" %eax)
37613 $test-add-mem-to-reg:initialize-var-register:
37614     # var1->register = "eax"
37615     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
37616     (copy-array Heap "eax" %eax)
37617 $test-add-mem-to-reg:initialize-var2:
37618     # var var2/edx: (payload var)
37619     68/push 0/imm32/register
37620     68/push 0/imm32/register
37621     68/push 8/imm32/stack-offset
37622     68/push 1/imm32/block-depth
37623     ff 6/subop/push *(ecx+0x10)
37624     68/push 0x11/imm32/alloc-id:fake
37625     68/push 0/imm32/name
37626     68/push 0/imm32/name
37627     68/push 0x11/imm32/alloc-id:fake:payload
37628     89/<- %edx 4/r32/esp
37629 $test-add-mem-to-reg:initialize-var2-name:
37630     # var2->name = "var2"
37631     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
37632     (copy-array Heap "var2" %eax)
37633 $test-add-mem-to-reg:initialize-inouts:
37634     # var inouts/esi: (payload stmt-var) = [var2]
37635     68/push 0/imm32/is-deref:false
37636     68/push 0/imm32/next
37637     68/push 0/imm32/next
37638     52/push-edx/var2
37639     68/push 0x11/imm32/alloc-id:fake
37640     68/push 0x11/imm32/alloc-id:fake:payload
37641     89/<- %esi 4/r32/esp
37642 $test-add-mem-to-reg:initialize-outputs:
37643     # var outputs/edi: (payload stmt-var) = [var1]
37644     68/push 0/imm32/is-deref:false
37645     68/push 0/imm32/next
37646     68/push 0/imm32/next
37647     51/push-ecx/var1
37648     68/push 0x11/imm32/alloc-id:fake
37649     68/push 0x11/imm32/alloc-id:fake:payload
37650     89/<- %edi 4/r32/esp
37651 $test-add-mem-to-reg:initialize-stmt:
37652     # var stmt/esi: (addr statement)
37653     68/push 0/imm32/next
37654     68/push 0/imm32/next
37655     57/push-edi/outputs
37656     68/push 0x11/imm32/alloc-id:fake
37657     56/push-esi/inouts
37658     68/push 0x11/imm32/alloc-id:fake
37659     68/push 0/imm32/operation
37660     68/push 0/imm32/operation
37661     68/push 1/imm32/tag:stmt1
37662     89/<- %esi 4/r32/esp
37663 $test-add-mem-to-reg:initialize-stmt-operation:
37664     # stmt->operation = "add"
37665     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
37666     (copy-array Heap "add" %eax)
37667     # convert
37668     c7 0/subop/copy *Curr-block-depth 0/imm32
37669     (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0)
37670     (flush _test-output-buffered-file)
37671 #?     # dump _test-output-stream {{{
37672 #?     (write 2 "^")
37673 #?     (write-stream 2 _test-output-stream)
37674 #?     (write 2 "$\n")
37675 #?     (rewind-stream _test-output-stream)
37676 #?     # }}}
37677     # check output
37678     (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg")
37679     # . epilogue
37680     89/<- %esp 5/r32/ebp
37681     5d/pop-to-ebp
37682     c3/return
37684 test-add-literal-to-eax:
37685     #   var1/eax <- add 0x34
37686     # =>
37687     #   05/add-to-eax 0x34/imm32
37688     #
37689     # . prologue
37690     55/push-ebp
37691     89/<- %ebp 4/r32/esp
37692     # setup
37693     (clear-stream _test-output-stream)
37694     (clear-stream $_test-output-buffered-file->buffer)
37695 $test-add-literal-to-eax:initialize-var-type:
37696     # var type/ecx: (payload type-tree) = int
37697     68/push 0/imm32/right:null
37698     68/push 0/imm32/right:null
37699     68/push 0/imm32/left:unused
37700     68/push 1/imm32/value:int
37701     68/push 1/imm32/is-atom?:true
37702     68/push 0x11/imm32/alloc-id:fake:payload
37703     89/<- %ecx 4/r32/esp
37704 $test-add-literal-to-eax:initialize-var:
37705     # var v/ecx: (payload var)
37706     68/push 0/imm32/register
37707     68/push 0/imm32/register
37708     68/push 0/imm32/no-stack-offset
37709     68/push 1/imm32/block-depth
37710     51/push-ecx
37711     68/push 0x11/imm32/alloc-id:fake
37712     68/push 0/imm32/name
37713     68/push 0/imm32/name
37714     68/push 0x11/imm32/alloc-id:fake:payload
37715     89/<- %ecx 4/r32/esp
37716 $test-add-literal-to-eax:initialize-var-name:
37717     # v->name = "v"
37718     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
37719     (copy-array Heap "v" %eax)
37720 $test-add-literal-to-eax:initialize-var-register:
37721     # v->register = "eax"
37722     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
37723     (copy-array Heap "eax" %eax)
37724 $test-add-literal-to-eax:initialize-literal-type:
37725     # var type/edx: (payload type-tree) = literal
37726     68/push 0/imm32/right:null
37727     68/push 0/imm32/right:null
37728     68/push 0/imm32/left:unused
37729     68/push 0/imm32/value:literal
37730     68/push 1/imm32/is-atom?:true
37731     68/push 0x11/imm32/alloc-id:fake:payload
37732     89/<- %edx 4/r32/esp
37733 $test-add-literal-to-eax:initialize-literal:
37734     # var l/edx: (payload var)
37735     68/push 0/imm32/register
37736     68/push 0/imm32/register
37737     68/push 0/imm32/no-stack-offset
37738     68/push 1/imm32/block-depth
37739     52/push-edx
37740     68/push 0x11/imm32/alloc-id:fake
37741     68/push 0/imm32/name
37742     68/push 0/imm32/name
37743     68/push 0x11/imm32/alloc-id:fake:payload
37744     89/<- %edx 4/r32/esp
37745 $test-add-literal-to-eax:initialize-literal-value:
37746     # l->name = "0x34"
37747     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
37748     (copy-array Heap "0x34" %eax)
37749 $test-add-literal-to-eax:initialize-inouts:
37750     # var inouts/esi: (payload stmt-var) = [l]
37751     68/push 0/imm32/is-deref:false
37752     68/push 0/imm32/next
37753     68/push 0/imm32/next
37754     52/push-edx/l
37755     68/push 0x11/imm32/alloc-id:fake
37756     68/push 0x11/imm32/alloc-id:fake:payload
37757     89/<- %esi 4/r32/esp
37758 $test-add-literal-to-eax:initialize-outputs:
37759     # var outputs/edi: (payload stmt-var) = [v]
37760     68/push 0/imm32/is-deref:false
37761     68/push 0/imm32/next
37762     68/push 0/imm32/next
37763     51/push-ecx/v
37764     68/push 0x11/imm32/alloc-id:fake
37765     68/push 0x11/imm32/alloc-id:fake:payload
37766     89/<- %edi 4/r32/esp
37767 $test-add-literal-to-eax:initialize-stmt:
37768     # var stmt/esi: (addr statement)
37769     68/push 0/imm32/next
37770     68/push 0/imm32/next
37771     57/push-edi/outputs
37772     68/push 0x11/imm32/alloc-id:fake
37773     56/push-esi/inouts
37774     68/push 0x11/imm32/alloc-id:fake
37775     68/push 0/imm32/operation
37776     68/push 0/imm32/operation
37777     68/push 1/imm32/tag:stmt1
37778     89/<- %esi 4/r32/esp
37779 $test-add-literal-to-eax:initialize-stmt-operation:
37780     # stmt->operation = "add"
37781     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
37782     (copy-array Heap "add" %eax)
37783     # convert
37784     c7 0/subop/copy *Curr-block-depth 0/imm32
37785     (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0)
37786     (flush _test-output-buffered-file)
37787 #?     # dump _test-output-stream {{{
37788 #?     (write 2 "^")
37789 #?     (write-stream 2 _test-output-stream)
37790 #?     (write 2 "$\n")
37791 #?     (rewind-stream _test-output-stream)
37792 #?     # }}}
37793     # check output
37794     (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax")
37795     # . epilogue
37796     89/<- %esp 5/r32/ebp
37797     5d/pop-to-ebp
37798     c3/return
37800 test-add-literal-to-reg:
37801     #   var1/ecx <- add 0x34
37802     # =>
37803     #   81 0/subop/add %ecx 0x34/imm32
37804     #
37805     # . prologue
37806     55/push-ebp
37807     89/<- %ebp 4/r32/esp
37808     # setup
37809     (clear-stream _test-output-stream)
37810     (clear-stream $_test-output-buffered-file->buffer)
37811 $test-add-literal-to-reg:initialize-var-type:
37812     # var type/ecx: (payload type-tree) = int
37813     68/push 0/imm32/right:null
37814     68/push 0/imm32/right:null
37815     68/push 0/imm32/left:unused
37816     68/push 1/imm32/value:int
37817     68/push 1/imm32/is-atom?:true
37818     68/push 0x11/imm32/alloc-id:fake:payload
37819     89/<- %ecx 4/r32/esp
37820 $test-add-literal-to-reg:initialize-var:
37821     # var v/ecx: (payload var)
37822     68/push 0/imm32/register
37823     68/push 0/imm32/register
37824     68/push 0/imm32/no-stack-offset
37825     68/push 1/imm32/block-depth
37826     51/push-ecx
37827     68/push 0x11/imm32/alloc-id:fake
37828     68/push 0/imm32/name
37829     68/push 0/imm32/name
37830     68/push 0x11/imm32/alloc-id:fake:payload
37831     89/<- %ecx 4/r32/esp
37832 $test-add-literal-to-reg:initialize-var-name:
37833     # v->name = "v"
37834     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
37835     (copy-array Heap "v" %eax)
37836 $test-add-literal-to-reg:initialize-var-register:
37837     # v->register = "ecx"
37838     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
37839     (copy-array Heap "ecx" %eax)
37840 $test-add-literal-to-reg:initialize-literal-type:
37841     # var type/edx: (payload type-tree) = literal
37842     68/push 0/imm32/right:null
37843     68/push 0/imm32/right:null
37844     68/push 0/imm32/left:unused
37845     68/push 0/imm32/value:literal
37846     68/push 1/imm32/is-atom?:true
37847     68/push 0x11/imm32/alloc-id:fake:payload
37848     89/<- %edx 4/r32/esp
37849 $test-add-literal-to-reg:initialize-literal:
37850     # var l/edx: (payload var)
37851     68/push 0/imm32/register
37852     68/push 0/imm32/register
37853     68/push 0/imm32/no-stack-offset
37854     68/push 1/imm32/block-depth
37855     52/push-edx
37856     68/push 0x11/imm32/alloc-id:fake
37857     68/push 0/imm32/name
37858     68/push 0/imm32/name
37859     68/push 0x11/imm32/alloc-id:fake:payload
37860     89/<- %edx 4/r32/esp
37861 $test-add-literal-to-reg:initialize-literal-value:
37862     # l->name = "0x34"
37863     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
37864     (copy-array Heap "0x34" %eax)
37865 $test-add-literal-to-reg:initialize-inouts:
37866     # var inouts/esi: (payload stmt-var) = [l]
37867     68/push 0/imm32/is-deref:false
37868     68/push 0/imm32/next
37869     68/push 0/imm32/next
37870     52/push-edx/l
37871     68/push 0x11/imm32/alloc-id:fake
37872     68/push 0x11/imm32/alloc-id:fake:payload
37873     89/<- %esi 4/r32/esp
37874 $test-add-literal-to-reg:initialize-outputs:
37875     # var outputs/edi: (payload stmt-var) = [v]
37876     68/push 0/imm32/is-deref:false
37877     68/push 0/imm32/next
37878     68/push 0/imm32/next
37879     51/push-ecx/v
37880     68/push 0x11/imm32/alloc-id:fake
37881     68/push 0x11/imm32/alloc-id:fake:payload
37882     89/<- %edi 4/r32/esp
37883 $test-add-literal-to-reg:initialize-stmt:
37884     # var stmt/esi: (addr statement)
37885     68/push 0/imm32/next
37886     68/push 0/imm32/next
37887     57/push-edi/outputs
37888     68/push 0x11/imm32/alloc-id:fake
37889     56/push-esi/inouts
37890     68/push 0x11/imm32/alloc-id:fake
37891     68/push 0/imm32/operation
37892     68/push 0/imm32/operation
37893     68/push 1/imm32/tag:stmt1
37894     89/<- %esi 4/r32/esp
37895 $test-add-literal-to-reg:initialize-stmt-operation:
37896     # stmt->operation = "add"
37897     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
37898     (copy-array Heap "add" %eax)
37899     # convert
37900     c7 0/subop/copy *Curr-block-depth 0/imm32
37901     (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0)
37902     (flush _test-output-buffered-file)
37903 #?     # dump _test-output-stream {{{
37904 #?     (write 2 "^")
37905 #?     (write-stream 2 _test-output-stream)
37906 #?     (write 2 "$\n")
37907 #?     (rewind-stream _test-output-stream)
37908 #?     # }}}
37909     # check output
37910     (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg")
37911     # . epilogue
37912     89/<- %esp 5/r32/ebp
37913     5d/pop-to-ebp
37914     c3/return
37916 test-add-literal-to-mem:
37917     #   add-to var1, 0x34
37918     # =>
37919     #   81 0/subop/add %eax 0x34/imm32
37920     #
37921     # . prologue
37922     55/push-ebp
37923     89/<- %ebp 4/r32/esp
37924     # setup
37925     (clear-stream _test-output-stream)
37926     (clear-stream $_test-output-buffered-file->buffer)
37927 $test-add-literal-to-mem:initialize-type:
37928     # var type/ecx: (payload type-tree) = int
37929     68/push 0/imm32/right:null
37930     68/push 0/imm32/right:null
37931     68/push 0/imm32/left:unused
37932     68/push 1/imm32/value:int
37933     68/push 1/imm32/is-atom?:true
37934     68/push 0x11/imm32/alloc-id:fake:payload
37935     89/<- %ecx 4/r32/esp
37936 $test-add-literal-to-mem:initialize-var1:
37937     # var var1/ecx: (payload var)
37938     68/push 0/imm32/register
37939     68/push 0/imm32/register
37940     68/push 8/imm32/stack-offset
37941     68/push 1/imm32/block-depth
37942     51/push-ecx
37943     68/push 0x11/imm32/alloc-id:fake
37944     68/push 0/imm32/name
37945     68/push 0/imm32/name
37946     68/push 0x11/imm32/alloc-id:fake:payload
37947     89/<- %ecx 4/r32/esp
37948 $test-add-literal-to-mem:initialize-var1-name:
37949     # var1->name = "var1"
37950     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
37951     (copy-array Heap "var1" %eax)
37952 $test-add-literal-to-mem:initialize-literal-type:
37953     # var type/edx: (payload type-tree) = literal
37954     68/push 0/imm32/right:null
37955     68/push 0/imm32/right:null
37956     68/push 0/imm32/left:unused
37957     68/push 0/imm32/value:literal
37958     68/push 1/imm32/is-atom?:true
37959     68/push 0x11/imm32/alloc-id:fake:payload
37960     89/<- %edx 4/r32/esp
37961 $test-add-literal-to-mem:initialize-literal:
37962     # var l/edx: (payload var)
37963     68/push 0/imm32/register
37964     68/push 0/imm32/register
37965     68/push 0/imm32/no-stack-offset
37966     68/push 1/imm32/block-depth
37967     52/push-edx
37968     68/push 0x11/imm32/alloc-id:fake
37969     68/push 0/imm32/name
37970     68/push 0/imm32/name
37971     68/push 0x11/imm32/alloc-id:fake:payload
37972     89/<- %edx 4/r32/esp
37973 $test-add-literal-to-mem:initialize-literal-value:
37974     # l->name = "0x34"
37975     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
37976     (copy-array Heap "0x34" %eax)
37977 $test-add-literal-to-mem:initialize-inouts:
37978     # var inouts/esi: (payload stmt-var) = [l]
37979     68/push 0/imm32/is-deref:false
37980     68/push 0/imm32/next
37981     68/push 0/imm32/next
37982     52/push-edx/l
37983     68/push 0x11/imm32/alloc-id:fake
37984     68/push 0x11/imm32/alloc-id:fake:payload
37985     89/<- %esi 4/r32/esp
37986     # var inouts = (handle stmt-var) = [var1, var2]
37987     68/push 0/imm32/is-deref:false
37988     56/push-esi/next
37989     68/push 0x11/imm32/alloc-id:fake
37990     51/push-ecx/var1
37991     68/push 0x11/imm32/alloc-id:fake
37992     68/push 0x11/imm32/alloc-id:fake:payload
37993     89/<- %esi 4/r32/esp
37994 $test-add-literal-to-mem:initialize-stmt:
37995     # var stmt/esi: (addr statement)
37996     68/push 0/imm32/next
37997     68/push 0/imm32/next
37998     68/push 0/imm32/outputs
37999     68/push 0/imm32/outputs
38000     56/push-esi/inouts
38001     68/push 0x11/imm32/alloc-id:fake
38002     68/push 0/imm32/operation
38003     68/push 0/imm32/operation
38004     68/push 1/imm32/tag:stmt1
38005     89/<- %esi 4/r32/esp
38006 $test-add-literal-to-mem:initialize-stmt-operation:
38007     # stmt->operation = "add-to"
38008     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
38009     (copy-array Heap "add-to" %eax)
38010     # convert
38011     c7 0/subop/copy *Curr-block-depth 0/imm32
38012     (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0)
38013     (flush _test-output-buffered-file)
38014 #?     # dump _test-output-stream {{{
38015 #?     (write 2 "^")
38016 #?     (write-stream 2 _test-output-stream)
38017 #?     (write 2 "$\n")
38018 #?     (rewind-stream _test-output-stream)
38019 #?     # }}}
38020     # check output
38021     (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem")
38022     # . epilogue
38023     89/<- %esp 5/r32/ebp
38024     5d/pop-to-ebp
38025     c3/return
38027 test-shift-reg-by-literal:
38028     #   var1/ecx <- shift-left 2
38029     # =>
38030     #   c1/shift 4/subop/left %ecx 2/imm8
38031     #
38032     # . prologue
38033     55/push-ebp
38034     89/<- %ebp 4/r32/esp
38035     # setup
38036     (clear-stream _test-output-stream)
38037     (clear-stream $_test-output-buffered-file->buffer)
38038 $test-shift-reg-by-literal:initialize-var-type:
38039     # var type/ecx: (payload type-tree) = int
38040     68/push 0/imm32/right:null
38041     68/push 0/imm32/right:null
38042     68/push 0/imm32/left:unused
38043     68/push 1/imm32/value:int
38044     68/push 1/imm32/is-atom?:true
38045     68/push 0x11/imm32/alloc-id:fake:payload
38046     89/<- %ecx 4/r32/esp
38047 $test-shift-reg-by-literal:initialize-var:
38048     # var v/ecx: (payload var)
38049     68/push 0/imm32/register
38050     68/push 0/imm32/register
38051     68/push 0/imm32/no-stack-offset
38052     68/push 1/imm32/block-depth
38053     51/push-ecx
38054     68/push 0x11/imm32/alloc-id:fake
38055     68/push 0/imm32/name
38056     68/push 0/imm32/name
38057     68/push 0x11/imm32/alloc-id:fake:payload
38058     89/<- %ecx 4/r32/esp
38059 $test-shift-reg-by-literal:initialize-var-name:
38060     # v->name = "v"
38061     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
38062     (copy-array Heap "v" %eax)
38063 $test-shift-reg-by-literal:initialize-var-register:
38064     # v->register = "ecx"
38065     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
38066     (copy-array Heap "ecx" %eax)
38067 $test-shift-reg-by-literal:initialize-literal-type:
38068     # var type/edx: (payload type-tree) = literal
38069     68/push 0/imm32/right:null
38070     68/push 0/imm32/right:null
38071     68/push 0/imm32/left:unused
38072     68/push 0/imm32/value:literal
38073     68/push 1/imm32/is-atom?:true
38074     68/push 0x11/imm32/alloc-id:fake:payload
38075     89/<- %edx 4/r32/esp
38076 $test-shift-reg-by-literal:initialize-literal:
38077     # var l/edx: (payload var)
38078     68/push 0/imm32/register
38079     68/push 0/imm32/register
38080     68/push 0/imm32/no-stack-offset
38081     68/push 1/imm32/block-depth
38082     52/push-edx
38083     68/push 0x11/imm32/alloc-id:fake
38084     68/push 0/imm32/name
38085     68/push 0/imm32/name
38086     68/push 0x11/imm32/alloc-id:fake:payload
38087     89/<- %edx 4/r32/esp
38088 $test-shift-reg-by-literal:initialize-literal-value:
38089     # l->name = "2"
38090     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
38091     (copy-array Heap "2" %eax)
38092 $test-shift-reg-by-literal:initialize-inouts:
38093     # var inouts/esi: (payload stmt-var) = [l]
38094     68/push 0/imm32/is-deref:false
38095     68/push 0/imm32/next
38096     68/push 0/imm32/next
38097     52/push-edx/l
38098     68/push 0x11/imm32/alloc-id:fake
38099     68/push 0x11/imm32/alloc-id:fake:payload
38100     89/<- %esi 4/r32/esp
38101 $test-shift-reg-by-literal:initialize-outputs:
38102     # var outputs/edi: (payload stmt-var) = [v]
38103     68/push 0/imm32/is-deref:false
38104     68/push 0/imm32/next
38105     68/push 0/imm32/next
38106     51/push-ecx/v
38107     68/push 0x11/imm32/alloc-id:fake
38108     68/push 0x11/imm32/alloc-id:fake:payload
38109     89/<- %edi 4/r32/esp
38110 $test-shift-reg-by-literal:initialize-stmt:
38111     # var stmt/esi: (addr statement)
38112     68/push 0/imm32/next
38113     68/push 0/imm32/next
38114     57/push-edi/outputs
38115     68/push 0x11/imm32/alloc-id:fake
38116     56/push-esi/inouts
38117     68/push 0x11/imm32/alloc-id:fake
38118     68/push 0/imm32/operation
38119     68/push 0/imm32/operation
38120     68/push 1/imm32/tag:stmt1
38121     89/<- %esi 4/r32/esp
38122 $test-shift-reg-by-literal:initialize-stmt-operation:
38123     # stmt->operation = "shift-left"
38124     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
38125     (copy-array Heap "shift-left" %eax)
38126     # convert
38127     c7 0/subop/copy *Curr-block-depth 0/imm32
38128     (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0)
38129     (flush _test-output-buffered-file)
38130 #?     # dump _test-output-stream {{{
38131 #?     (write 2 "^")
38132 #?     (write-stream 2 _test-output-stream)
38133 #?     (write 2 "$\n")
38134 #?     (rewind-stream _test-output-stream)
38135 #?     # }}}
38136     # check output
38137     (check-next-stream-line-equal _test-output-stream "c1/shift 4/subop/left %ecx 2/imm8" "F - test-shift-reg-by-literal")
38138     # . epilogue
38139     89/<- %esp 5/r32/ebp
38140     5d/pop-to-ebp
38141     c3/return
38143 test-shift-mem-by-literal:
38144     #   shift-left var 3
38145     # =>
38146     #   c1/shift 4/subop/left *(ebp+8) 3/imm8
38147     #
38148     # . prologue
38149     55/push-ebp
38150     89/<- %ebp 4/r32/esp
38151     # setup
38152     (clear-stream _test-output-stream)
38153     (clear-stream $_test-output-buffered-file->buffer)
38154 $test-shift-mem-by-literal:initialize-type:
38155     # var type/ecx: (payload type-tree) = int
38156     68/push 0/imm32/right:null
38157     68/push 0/imm32/right:null
38158     68/push 0/imm32/left:unused
38159     68/push 1/imm32/value:int
38160     68/push 1/imm32/is-atom?:true
38161     68/push 0x11/imm32/alloc-id:fake:payload
38162     89/<- %ecx 4/r32/esp
38163 $test-shift-mem-by-literal:initialize-var1:
38164     # var var1/ecx: (payload var)
38165     68/push 0/imm32/register
38166     68/push 0/imm32/register
38167     68/push 8/imm32/stack-offset
38168     68/push 1/imm32/block-depth
38169     51/push-ecx
38170     68/push 0x11/imm32/alloc-id:fake
38171     68/push 0/imm32/name
38172     68/push 0/imm32/name
38173     68/push 0x11/imm32/alloc-id:fake:payload
38174     89/<- %ecx 4/r32/esp
38175 $test-shift-mem-by-literal:initialize-var1-name:
38176     # var1->name = "var1"
38177     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
38178     (copy-array Heap "var1" %eax)
38179 $test-shift-mem-by-literal:initialize-literal-type:
38180     # var type/edx: (payload type-tree) = literal
38181     68/push 0/imm32/right:null
38182     68/push 0/imm32/right:null
38183     68/push 0/imm32/left:unused
38184     68/push 0/imm32/value:literal
38185     68/push 1/imm32/is-atom?:true
38186     68/push 0x11/imm32/alloc-id:fake:payload
38187     89/<- %edx 4/r32/esp
38188 $test-shift-mem-by-literal:initialize-literal:
38189     # var l/edx: (payload var)
38190     68/push 0/imm32/register
38191     68/push 0/imm32/register
38192     68/push 0/imm32/no-stack-offset
38193     68/push 1/imm32/block-depth
38194     52/push-edx
38195     68/push 0x11/imm32/alloc-id:fake
38196     68/push 0/imm32/name
38197     68/push 0/imm32/name
38198     68/push 0x11/imm32/alloc-id:fake:payload
38199     89/<- %edx 4/r32/esp
38200 $test-shift-mem-by-literal:initialize-literal-value:
38201     # l->name = "3"
38202     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
38203     (copy-array Heap "3" %eax)
38204 $test-shift-mem-by-literal:initialize-inouts:
38205     # var inouts/esi: (payload stmt-var) = [l]
38206     68/push 0/imm32/is-deref:false
38207     68/push 0/imm32/next
38208     68/push 0/imm32/next
38209     52/push-edx/l
38210     68/push 0x11/imm32/alloc-id:fake
38211     68/push 0x11/imm32/alloc-id:fake:payload
38212     89/<- %esi 4/r32/esp
38213     # var inouts = (handle stmt-var) = [var1, var2]
38214     68/push 0/imm32/is-deref:false
38215     56/push-esi/next
38216     68/push 0x11/imm32/alloc-id:fake
38217     51/push-ecx/var1
38218     68/push 0x11/imm32/alloc-id:fake
38219     68/push 0x11/imm32/alloc-id:fake:payload
38220     89/<- %esi 4/r32/esp
38221 $test-shift-mem-by-literal:initialize-stmt:
38222     # var stmt/esi: (addr statement)
38223     68/push 0/imm32/next
38224     68/push 0/imm32/next
38225     68/push 0/imm32/outputs
38226     68/push 0/imm32/outputs
38227     56/push-esi/inouts
38228     68/push 0x11/imm32/alloc-id:fake
38229     68/push 0/imm32/operation
38230     68/push 0/imm32/operation
38231     68/push 1/imm32/tag:stmt1
38232     89/<- %esi 4/r32/esp
38233 $test-shift-mem-by-literal:initialize-stmt-operation:
38234     # stmt->operation = "shift-left"
38235     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
38236     (copy-array Heap "shift-left" %eax)
38237     # convert
38238     c7 0/subop/copy *Curr-block-depth 0/imm32
38239     (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0)
38240     (flush _test-output-buffered-file)
38241 #?     # dump _test-output-stream {{{
38242 #?     (write 2 "^")
38243 #?     (write-stream 2 _test-output-stream)
38244 #?     (write 2 "$\n")
38245 #?     (rewind-stream _test-output-stream)
38246 #?     # }}}
38247     # check output
38248     (check-next-stream-line-equal _test-output-stream "c1/shift 4/subop/left *(ebp+0x00000008) 3/imm8" "F - test-shift-mem-by-literal")
38249     # . epilogue
38250     89/<- %esp 5/r32/ebp
38251     5d/pop-to-ebp
38252     c3/return
38254 test-compare-reg-with-reg:
38255     #   compare var1/ecx, var2/eax
38256     # =>
38257     #   39/compare %ecx 0/r32/eax
38258     #
38259     # . prologue
38260     55/push-ebp
38261     89/<- %ebp 4/r32/esp
38262     # setup
38263     (clear-stream _test-output-stream)
38264     (clear-stream $_test-output-buffered-file->buffer)
38265 $test-compare-reg-with-reg:initialize-type:
38266     # var type/ecx: (payload type-tree) = int
38267     68/push 0/imm32/right:null
38268     68/push 0/imm32/right:null
38269     68/push 0/imm32/left:unused
38270     68/push 1/imm32/value:int
38271     68/push 1/imm32/is-atom?:true
38272     68/push 0x11/imm32/alloc-id:fake:payload
38273     89/<- %ecx 4/r32/esp
38274 $test-compare-reg-with-reg:initialize-var1:
38275     # var var1/ecx: (payload var)
38276     68/push 0/imm32/register
38277     68/push 0/imm32/register
38278     68/push 0/imm32/no-stack-offset
38279     68/push 1/imm32/block-depth
38280     51/push-ecx
38281     68/push 0x11/imm32/alloc-id:fake
38282     68/push 0/imm32/name
38283     68/push 0/imm32/name
38284     68/push 0x11/imm32/alloc-id:fake:payload
38285     89/<- %ecx 4/r32/esp
38286 $test-compare-reg-with-reg:initialize-var1-name:
38287     # var1->name = "var1"
38288     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
38289     (copy-array Heap "var1" %eax)
38290 $test-compare-reg-with-reg:initialize-var1-register:
38291     # var1->register = "ecx"
38292     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
38293     (copy-array Heap "ecx" %eax)
38294 $test-compare-reg-with-reg:initialize-var2:
38295     # var var2/edx: (payload var)
38296     68/push 0/imm32/register
38297     68/push 0/imm32/register
38298     68/push 0/imm32/no-stack-offset
38299     68/push 1/imm32/block-depth
38300     ff 6/subop/push *(ecx+0x10)
38301     68/push 0x11/imm32/alloc-id:fake
38302     68/push 0/imm32/name
38303     68/push 0/imm32/name
38304     68/push 0x11/imm32/alloc-id:fake:payload
38305     89/<- %edx 4/r32/esp
38306 $test-compare-reg-with-reg:initialize-var2-name:
38307     # var2->name = "var2"
38308     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
38309     (copy-array Heap "var2" %eax)
38310 $test-compare-reg-with-reg:initialize-var2-register:
38311     # var2->register = "eax"
38312     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
38313     (copy-array Heap "eax" %eax)
38314 $test-compare-reg-with-reg:initialize-inouts:
38315     # var inouts/esi: (payload stmt-var) = [var2]
38316     68/push 0/imm32/is-deref:false
38317     68/push 0/imm32/next
38318     68/push 0/imm32/next
38319     52/push-edx/var2
38320     68/push 0x11/imm32/alloc-id:fake
38321     68/push 0x11/imm32/alloc-id:fake:payload
38322     89/<- %esi 4/r32/esp
38323     # inouts = [var1, var2]
38324     68/push 0/imm32/is-deref:false
38325     56/push-esi/next
38326     68/push 0x11/imm32/alloc-id:fake
38327     51/push-ecx/var1
38328     68/push 0x11/imm32/alloc-id:fake
38329     68/push 0x11/imm32/alloc-id:fake:payload
38330     89/<- %esi 4/r32/esp
38331 $test-compare-reg-with-reg:initialize-stmt:
38332     # var stmt/esi: (addr statement)
38333     68/push 0/imm32/next
38334     68/push 0/imm32/next
38335     68/push 0/imm32/outputs
38336     68/push 0/imm32/outputs
38337     56/push-esi/inouts
38338     68/push 0x11/imm32/alloc-id:fake
38339     68/push 0/imm32/operation
38340     68/push 0/imm32/operation
38341     68/push 1/imm32/tag:stmt1
38342     89/<- %esi 4/r32/esp
38343 $test-compare-reg-with-reg:initialize-stmt-operation:
38344     # stmt->operation = "compare"
38345     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
38346     (copy-array Heap "compare" %eax)
38347     # convert
38348     c7 0/subop/copy *Curr-block-depth 0/imm32
38349     (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0)
38350     (flush _test-output-buffered-file)
38351 #?     # dump _test-output-stream {{{
38352 #?     (write 2 "^")
38353 #?     (write-stream 2 _test-output-stream)
38354 #?     (write 2 "$\n")
38355 #?     (rewind-stream _test-output-stream)
38356 #?     # }}}
38357     # check output
38358     (check-next-stream-line-equal _test-output-stream "39/compare-> %ecx 0x00000000/r32" "F - test-compare-reg-with-reg")
38359     # . epilogue
38360     89/<- %esp 5/r32/ebp
38361     5d/pop-to-ebp
38362     c3/return
38364 test-compare-mem-with-reg:
38365     #   compare var1, var2/eax
38366     # =>
38367     #   39/compare *(ebp+___) 0/r32/eax
38368     #
38369     # . prologue
38370     55/push-ebp
38371     89/<- %ebp 4/r32/esp
38372     # setup
38373     (clear-stream _test-output-stream)
38374     (clear-stream $_test-output-buffered-file->buffer)
38375 $test-compare-mem-with-reg:initialize-type:
38376     # var type/ecx: (payload type-tree) = int
38377     68/push 0/imm32/right:null
38378     68/push 0/imm32/right:null
38379     68/push 0/imm32/left:unused
38380     68/push 1/imm32/value:int
38381     68/push 1/imm32/is-atom?:true
38382     68/push 0x11/imm32/alloc-id:fake:payload
38383     89/<- %ecx 4/r32/esp
38384 $test-compare-mem-with-reg:initialize-var1:
38385     # var var1/ecx: (payload var)
38386     68/push 0/imm32/register
38387     68/push 0/imm32/register
38388     68/push 8/imm32/stack-offset
38389     68/push 1/imm32/block-depth
38390     51/push-ecx
38391     68/push 0x11/imm32/alloc-id:fake
38392     68/push 0/imm32/name
38393     68/push 0/imm32/name
38394     68/push 0x11/imm32/alloc-id:fake:payload
38395     89/<- %ecx 4/r32/esp
38396 $test-compare-mem-with-reg:initialize-var1-name:
38397     # var1->name = "var1"
38398     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
38399     (copy-array Heap "var1" %eax)
38400 $test-compare-mem-with-reg:initialize-var2:
38401     # var var2/edx: (payload var)
38402     68/push 0/imm32/register
38403     68/push 0/imm32/register
38404     68/push 0/imm32/no-stack-offset
38405     68/push 1/imm32/block-depth
38406     ff 6/subop/push *(ecx+0x10)
38407     68/push 0x11/imm32/alloc-id:fake
38408     68/push 0/imm32/name
38409     68/push 0/imm32/name
38410     68/push 0x11/imm32/alloc-id:fake:payload
38411     89/<- %edx 4/r32/esp
38412 $test-compare-mem-with-reg:initialize-var2-name:
38413     # var2->name = "var2"
38414     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
38415     (copy-array Heap "var2" %eax)
38416 $test-compare-mem-with-reg:initialize-var2-register:
38417     # var2->register = "eax"
38418     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
38419     (copy-array Heap "eax" %eax)
38420 $test-compare-mem-with-reg:initialize-inouts:
38421     # var inouts/esi: (payload stmt-var) = [var2]
38422     68/push 0/imm32/is-deref:false
38423     68/push 0/imm32/next
38424     68/push 0/imm32/next
38425     52/push-edx/var2
38426     68/push 0x11/imm32/alloc-id:fake
38427     68/push 0x11/imm32/alloc-id:fake:payload
38428     89/<- %esi 4/r32/esp
38429     # inouts = [var1, var2]
38430     68/push 0/imm32/is-deref:false
38431     56/push-esi/next
38432     68/push 0x11/imm32/alloc-id:fake
38433     51/push-ecx/var1
38434     68/push 0x11/imm32/alloc-id:fake
38435     68/push 0x11/imm32/alloc-id:fake:payload
38436     89/<- %esi 4/r32/esp
38437 $test-compare-mem-with-reg:initialize-stmt:
38438     # var stmt/esi: (addr statement)
38439     68/push 0/imm32/next
38440     68/push 0/imm32/next
38441     68/push 0/imm32/outputs
38442     68/push 0/imm32/outputs
38443     56/push-esi/inouts
38444     68/push 0x11/imm32/alloc-id:fake
38445     68/push 0/imm32/operation
38446     68/push 0/imm32/operation
38447     68/push 1/imm32/tag:stmt1
38448     89/<- %esi 4/r32/esp
38449 $test-compare-mem-with-reg:initialize-stmt-operation:
38450     # stmt->operation = "compare"
38451     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
38452     (copy-array Heap "compare" %eax)
38453     # convert
38454     c7 0/subop/copy *Curr-block-depth 0/imm32
38455     (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0)
38456     (flush _test-output-buffered-file)
38457 #?     # dump _test-output-stream {{{
38458 #?     (write 2 "^")
38459 #?     (write-stream 2 _test-output-stream)
38460 #?     (write 2 "$\n")
38461 #?     (rewind-stream _test-output-stream)
38462 #?     # }}}
38463     # check output
38464     (check-next-stream-line-equal _test-output-stream "39/compare-> *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-mem-with-reg")
38465     # . epilogue
38466     89/<- %esp 5/r32/ebp
38467     5d/pop-to-ebp
38468     c3/return
38470 test-compare-reg-with-mem:
38471     #   compare var1/eax, var2
38472     # =>
38473     #   3b/compare<- *(ebp+___) 0/r32/eax
38474     #
38475     # . prologue
38476     55/push-ebp
38477     89/<- %ebp 4/r32/esp
38478     # setup
38479     (clear-stream _test-output-stream)
38480     (clear-stream $_test-output-buffered-file->buffer)
38481 $test-compare-reg-with-mem:initialize-type:
38482     # var type/ecx: (payload type-tree) = int
38483     68/push 0/imm32/right:null
38484     68/push 0/imm32/right:null
38485     68/push 0/imm32/left:unused
38486     68/push 1/imm32/value:int
38487     68/push 1/imm32/is-atom?:true
38488     68/push 0x11/imm32/alloc-id:fake:payload
38489     89/<- %ecx 4/r32/esp
38490 $test-compare-reg-with-mem:initialize-var1:
38491     # var var1/ecx: (payload var)
38492     68/push 0/imm32/register
38493     68/push 0/imm32/register
38494     68/push 0/imm32/no-stack-offset
38495     68/push 1/imm32/block-depth
38496     51/push-ecx
38497     68/push 0x11/imm32/alloc-id:fake
38498     68/push 0/imm32/name
38499     68/push 0/imm32/name
38500     68/push 0x11/imm32/alloc-id:fake:payload
38501     89/<- %ecx 4/r32/esp
38502 $test-compare-reg-with-mem:initialize-var1-name:
38503     # var1->name = "var1"
38504     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
38505     (copy-array Heap "var1" %eax)
38506 $test-compare-reg-with-mem:initialize-var1-register:
38507     # var1->register = "eax"
38508     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
38509     (copy-array Heap "eax" %eax)
38510 $test-compare-reg-with-mem:initialize-var2:
38511     # var var2/edx: (payload var)
38512     68/push 0/imm32/register
38513     68/push 0/imm32/register
38514     68/push 8/imm32/stack-offset
38515     68/push 1/imm32/block-depth
38516     ff 6/subop/push *(ecx+0x10)
38517     68/push 0x11/imm32/alloc-id:fake
38518     68/push 0/imm32/name
38519     68/push 0/imm32/name
38520     68/push 0x11/imm32/alloc-id:fake:payload
38521     89/<- %edx 4/r32/esp
38522 $test-compare-reg-with-mem:initialize-var2-name:
38523     # var2->name = "var2"
38524     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
38525     (copy-array Heap "var2" %eax)
38526 $test-compare-reg-with-mem:initialize-inouts:
38527     # var inouts/esi: (payload stmt-var) = [var2]
38528     68/push 0/imm32/is-deref:false
38529     68/push 0/imm32/next
38530     68/push 0/imm32/next
38531     52/push-edx/var2
38532     68/push 0x11/imm32/alloc-id:fake
38533     68/push 0x11/imm32/alloc-id:fake:payload
38534     89/<- %esi 4/r32/esp
38535     # inouts = [var1, var2]
38536     68/push 0/imm32/is-deref:false
38537     56/push-esi/next
38538     68/push 0x11/imm32/alloc-id:fake
38539     51/push-ecx/var1
38540     68/push 0x11/imm32/alloc-id:fake
38541     68/push 0x11/imm32/alloc-id:fake:payload
38542     89/<- %esi 4/r32/esp
38543 $test-compare-reg-with-mem:initialize-stmt:
38544     # var stmt/esi: (addr statement)
38545     68/push 0/imm32/next
38546     68/push 0/imm32/next
38547     68/push 0/imm32/outputs
38548     68/push 0/imm32/outputs
38549     56/push-esi/inouts
38550     68/push 0x11/imm32/alloc-id:fake
38551     68/push 0/imm32/operation
38552     68/push 0/imm32/operation
38553     68/push 1/imm32/tag:stmt1
38554     89/<- %esi 4/r32/esp
38555 $test-compare-reg-with-mem:initialize-stmt-operation:
38556     # stmt->operation = "compare"
38557     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
38558     (copy-array Heap "compare" %eax)
38559     # convert
38560     c7 0/subop/copy *Curr-block-depth 0/imm32
38561     (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0)
38562     (flush _test-output-buffered-file)
38563 #?     # dump _test-output-stream {{{
38564 #?     (write 2 "^")
38565 #?     (write-stream 2 _test-output-stream)
38566 #?     (write 2 "$\n")
38567 #?     (rewind-stream _test-output-stream)
38568 #?     # }}}
38569     # check output
38570     (check-next-stream-line-equal _test-output-stream "3b/compare<- *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-reg-with-mem")
38571     # . epilogue
38572     89/<- %esp 5/r32/ebp
38573     5d/pop-to-ebp
38574     c3/return
38576 test-compare-mem-with-literal:
38577     #   compare var1, 0x34
38578     # =>
38579     #   81 7/subop/compare *(ebp+___) 0x34/imm32
38580     #
38581     # . prologue
38582     55/push-ebp
38583     89/<- %ebp 4/r32/esp
38584     # setup
38585     (clear-stream _test-output-stream)
38586     (clear-stream $_test-output-buffered-file->buffer)
38587 $test-compare-mem-with-literal:initialize-type:
38588     # var type/ecx: (payload type-tree) = int
38589     68/push 0/imm32/right:null
38590     68/push 0/imm32/right:null
38591     68/push 0/imm32/left:unused
38592     68/push 1/imm32/value:int
38593     68/push 1/imm32/is-atom?:true
38594     68/push 0x11/imm32/alloc-id:fake:payload
38595     89/<- %ecx 4/r32/esp
38596 $test-compare-mem-with-literal:initialize-var1:
38597     # var var1/ecx: (payload var)
38598     68/push 0/imm32/register
38599     68/push 0/imm32/register
38600     68/push 8/imm32/stack-offset
38601     68/push 1/imm32/block-depth
38602     51/push-ecx
38603     68/push 0x11/imm32/alloc-id:fake
38604     68/push 0/imm32/name
38605     68/push 0/imm32/name
38606     68/push 0x11/imm32/alloc-id:fake:payload
38607     89/<- %ecx 4/r32/esp
38608 $test-compare-mem-with-literal:initialize-var1-name:
38609     # var1->name = "var1"
38610     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
38611     (copy-array Heap "var1" %eax)
38612 $test-compare-mem-with-literal:initialize-literal-type:
38613     # var type/edx: (payload type-tree) = literal
38614     68/push 0/imm32/right:null
38615     68/push 0/imm32/right:null
38616     68/push 0/imm32/left:unused
38617     68/push 0/imm32/value:literal
38618     68/push 1/imm32/is-atom?:true
38619     68/push 0x11/imm32/alloc-id:fake:payload
38620     89/<- %edx 4/r32/esp
38621 $test-compare-mem-with-literal:initialize-literal:
38622     # var l/edx: (payload var)
38623     68/push 0/imm32/register
38624     68/push 0/imm32/register
38625     68/push 0/imm32/no-stack-offset
38626     68/push 1/imm32/block-depth
38627     52/push-edx
38628     68/push 0x11/imm32/alloc-id:fake
38629     68/push 0/imm32/name
38630     68/push 0/imm32/name
38631     68/push 0x11/imm32/alloc-id:fake:payload
38632     89/<- %edx 4/r32/esp
38633 $test-compare-mem-with-literal:initialize-literal-value:
38634     # l->name = "0x34"
38635     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
38636     (copy-array Heap "0x34" %eax)
38637 $test-compare-mem-with-literal:initialize-inouts:
38638     # var inouts/esi: (payload stmt-var) = [l]
38639     68/push 0/imm32/is-deref:false
38640     68/push 0/imm32/next
38641     68/push 0/imm32/next
38642     52/push-edx/l
38643     68/push 0x11/imm32/alloc-id:fake
38644     68/push 0x11/imm32/alloc-id:fake:payload
38645     89/<- %esi 4/r32/esp
38646     # var inouts = (handle stmt-var) = [var1, var2]
38647     68/push 0/imm32/is-deref:false
38648     56/push-esi/next
38649     68/push 0x11/imm32/alloc-id:fake
38650     51/push-ecx/var1
38651     68/push 0x11/imm32/alloc-id:fake
38652     68/push 0x11/imm32/alloc-id:fake:payload
38653     89/<- %esi 4/r32/esp
38654 $test-compare-mem-with-literal:initialize-stmt:
38655     # var stmt/esi: (addr statement)
38656     68/push 0/imm32/next
38657     68/push 0/imm32/next
38658     68/push 0/imm32/outputs
38659     68/push 0/imm32/outputs
38660     56/push-esi/inouts
38661     68/push 0x11/imm32/alloc-id:fake
38662     68/push 0/imm32/operation
38663     68/push 0/imm32/operation
38664     68/push 1/imm32/tag:stmt1
38665     89/<- %esi 4/r32/esp
38666 $test-compare-mem-with-literal:initialize-stmt-operation:
38667     # stmt->operation = "compare"
38668     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
38669     (copy-array Heap "compare" %eax)
38670     # convert
38671     c7 0/subop/copy *Curr-block-depth 0/imm32
38672     (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0)
38673     (flush _test-output-buffered-file)
38674 #?     # dump _test-output-stream {{{
38675 #?     (write 2 "^")
38676 #?     (write-stream 2 _test-output-stream)
38677 #?     (write 2 "$\n")
38678 #?     (rewind-stream _test-output-stream)
38679 #?     # }}}
38680     # check output
38681     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare *(ebp+0x00000008) 0x34/imm32" "F - test-compare-mem-with-literal")
38682     # . epilogue
38683     89/<- %esp 5/r32/ebp
38684     5d/pop-to-ebp
38685     c3/return
38687 test-compare-eax-with-literal:
38688     #   compare var1/eax 0x34
38689     # =>
38690     #   3d/compare-eax-with 0x34/imm32
38691     #
38692     # . prologue
38693     55/push-ebp
38694     89/<- %ebp 4/r32/esp
38695     # setup
38696     (clear-stream _test-output-stream)
38697     (clear-stream $_test-output-buffered-file->buffer)
38698 $test-compare-eax-with-literal:initialize-type:
38699     # var type/ecx: (payload type-tree) = int
38700     68/push 0/imm32/right:null
38701     68/push 0/imm32/right:null
38702     68/push 0/imm32/left:unused
38703     68/push 1/imm32/value:int
38704     68/push 1/imm32/is-atom?:true
38705     68/push 0x11/imm32/alloc-id:fake:payload
38706     89/<- %ecx 4/r32/esp
38707 $test-compare-eax-with-literal:initialize-var1:
38708     # var var1/ecx: (payload var)
38709     68/push 0/imm32/register
38710     68/push 0/imm32/register
38711     68/push 0/imm32/no-stack-offset
38712     68/push 1/imm32/block-depth
38713     51/push-ecx
38714     68/push 0x11/imm32/alloc-id:fake
38715     68/push 0/imm32/name
38716     68/push 0/imm32/name
38717     68/push 0x11/imm32/alloc-id:fake:payload
38718     89/<- %ecx 4/r32/esp
38719 $test-compare-eax-with-literal:initialize-var1-name:
38720     # var1->name = "var1"
38721     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
38722     (copy-array Heap "var1" %eax)
38723 $test-compare-eax-with-literal:initialize-var1-register:
38724     # v->register = "eax"
38725     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
38726     (copy-array Heap "eax" %eax)
38727 $test-compare-eax-with-literal:initialize-literal-type:
38728     # var type/edx: (payload type-tree) = literal
38729     68/push 0/imm32/right:null
38730     68/push 0/imm32/right:null
38731     68/push 0/imm32/left:unused
38732     68/push 0/imm32/value:literal
38733     68/push 1/imm32/is-atom?:true
38734     68/push 0x11/imm32/alloc-id:fake:payload
38735     89/<- %edx 4/r32/esp
38736 $test-compare-eax-with-literal:initialize-literal:
38737     # var l/edx: (payload var)
38738     68/push 0/imm32/register
38739     68/push 0/imm32/register
38740     68/push 0/imm32/no-stack-offset
38741     68/push 1/imm32/block-depth
38742     52/push-edx
38743     68/push 0x11/imm32/alloc-id:fake
38744     68/push 0/imm32/name
38745     68/push 0/imm32/name
38746     68/push 0x11/imm32/alloc-id:fake:payload
38747     89/<- %edx 4/r32/esp
38748 $test-compare-eax-with-literal:initialize-literal-value:
38749     # l->name = "0x34"
38750     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
38751     (copy-array Heap "0x34" %eax)
38752 $test-compare-eax-with-literal:initialize-inouts:
38753     # var inouts/esi: (payload stmt-var) = [l]
38754     68/push 0/imm32/is-deref:false
38755     68/push 0/imm32/next
38756     68/push 0/imm32/next
38757     52/push-edx/l
38758     68/push 0x11/imm32/alloc-id:fake
38759     68/push 0x11/imm32/alloc-id:fake:payload
38760     89/<- %esi 4/r32/esp
38761     # var inouts = (handle stmt-var) = [var1, var2]
38762     68/push 0/imm32/is-deref:false
38763     56/push-esi/next
38764     68/push 0x11/imm32/alloc-id:fake
38765     51/push-ecx/var1
38766     68/push 0x11/imm32/alloc-id:fake
38767     68/push 0x11/imm32/alloc-id:fake:payload
38768     89/<- %esi 4/r32/esp
38769 $test-compare-eax-with-literal:initialize-stmt:
38770     # var stmt/esi: (addr statement)
38771     68/push 0/imm32/next
38772     68/push 0/imm32/next
38773     68/push 0/imm32/outputs
38774     68/push 0/imm32/outputs
38775     56/push-esi/inouts
38776     68/push 0x11/imm32/alloc-id:fake
38777     68/push 0/imm32/operation
38778     68/push 0/imm32/operation
38779     68/push 1/imm32/tag:stmt1
38780     89/<- %esi 4/r32/esp
38781 $test-compare-eax-with-literal:initialize-stmt-operation:
38782     # stmt->operation = "compare"
38783     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
38784     (copy-array Heap "compare" %eax)
38785     # convert
38786     c7 0/subop/copy *Curr-block-depth 0/imm32
38787     (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0)
38788     (flush _test-output-buffered-file)
38789 #?     # dump _test-output-stream {{{
38790 #?     (write 2 "^")
38791 #?     (write-stream 2 _test-output-stream)
38792 #?     (write 2 "$\n")
38793 #?     (rewind-stream _test-output-stream)
38794 #?     # }}}
38795     # check output
38796     (check-next-stream-line-equal _test-output-stream "3d/compare-eax-with 0x34/imm32" "F - test-compare-eax-with-literal")
38797     # . epilogue
38798     89/<- %esp 5/r32/ebp
38799     5d/pop-to-ebp
38800     c3/return
38802 test-compare-reg-with-literal:
38803     #   compare var1/ecx 0x34
38804     # =>
38805     #   81 7/subop/compare %ecx 0x34/imm32
38806     #
38807     # . prologue
38808     55/push-ebp
38809     89/<- %ebp 4/r32/esp
38810     # setup
38811     (clear-stream _test-output-stream)
38812     (clear-stream $_test-output-buffered-file->buffer)
38813 $test-compare-reg-with-literal:initialize-type:
38814     # var type/ecx: (payload type-tree) = int
38815     68/push 0/imm32/right:null
38816     68/push 0/imm32/right:null
38817     68/push 0/imm32/left:unused
38818     68/push 1/imm32/value:int
38819     68/push 1/imm32/is-atom?:true
38820     68/push 0x11/imm32/alloc-id:fake:payload
38821     89/<- %ecx 4/r32/esp
38822 $test-compare-reg-with-literal:initialize-var1:
38823     # var var1/ecx: (payload var)
38824     68/push 0/imm32/register
38825     68/push 0/imm32/register
38826     68/push 0/imm32/no-stack-offset
38827     68/push 1/imm32/block-depth
38828     51/push-ecx
38829     68/push 0x11/imm32/alloc-id:fake
38830     68/push 0/imm32/name
38831     68/push 0/imm32/name
38832     68/push 0x11/imm32/alloc-id:fake:payload
38833     89/<- %ecx 4/r32/esp
38834 $test-compare-reg-with-literal:initialize-var1-name:
38835     # var1->name = "var1"
38836     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
38837     (copy-array Heap "var1" %eax)
38838 $test-compare-reg-with-literal:initialize-var1-register:
38839     # v->register = "ecx"
38840     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
38841     (copy-array Heap "ecx" %eax)
38842 $test-compare-reg-with-literal:initialize-literal-type:
38843     # var type/edx: (payload type-tree) = literal
38844     68/push 0/imm32/right:null
38845     68/push 0/imm32/right:null
38846     68/push 0/imm32/left:unused
38847     68/push 0/imm32/value:literal
38848     68/push 1/imm32/is-atom?:true
38849     68/push 0x11/imm32/alloc-id:fake:payload
38850     89/<- %edx 4/r32/esp
38851 $test-compare-reg-with-literal:initialize-literal:
38852     # var l/edx: (payload var)
38853     68/push 0/imm32/register
38854     68/push 0/imm32/register
38855     68/push 0/imm32/no-stack-offset
38856     68/push 1/imm32/block-depth
38857     52/push-edx
38858     68/push 0x11/imm32/alloc-id:fake
38859     68/push 0/imm32/name
38860     68/push 0/imm32/name
38861     68/push 0x11/imm32/alloc-id:fake:payload
38862     89/<- %edx 4/r32/esp
38863 $test-compare-reg-with-literal:initialize-literal-value:
38864     # l->name = "0x34"
38865     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
38866     (copy-array Heap "0x34" %eax)
38867 $test-compare-reg-with-literal:initialize-inouts:
38868     # var inouts/esi: (payload stmt-var) = [l]
38869     68/push 0/imm32/is-deref:false
38870     68/push 0/imm32/next
38871     68/push 0/imm32/next
38872     52/push-edx/l
38873     68/push 0x11/imm32/alloc-id:fake
38874     68/push 0x11/imm32/alloc-id:fake:payload
38875     89/<- %esi 4/r32/esp
38876     # var inouts = (handle stmt-var) = [var1, var2]
38877     68/push 0/imm32/is-deref:false
38878     56/push-esi/next
38879     68/push 0x11/imm32/alloc-id:fake
38880     51/push-ecx/var1
38881     68/push 0x11/imm32/alloc-id:fake
38882     68/push 0x11/imm32/alloc-id:fake:payload
38883     89/<- %esi 4/r32/esp
38884 $test-compare-reg-with-literal:initialize-stmt:
38885     # var stmt/esi: (addr statement)
38886     68/push 0/imm32/next
38887     68/push 0/imm32/next
38888     68/push 0/imm32/outputs
38889     68/push 0/imm32/outputs
38890     56/push-esi/inouts
38891     68/push 0x11/imm32/alloc-id:fake
38892     68/push 0/imm32/operation
38893     68/push 0/imm32/operation
38894     68/push 1/imm32/tag:stmt1
38895     89/<- %esi 4/r32/esp
38896 $test-compare-reg-with-literal:initialize-stmt-operation:
38897     # stmt->operation = "compare"
38898     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
38899     (copy-array Heap "compare" %eax)
38900     # convert
38901     c7 0/subop/copy *Curr-block-depth 0/imm32
38902     (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0)
38903     (flush _test-output-buffered-file)
38904 #?     # dump _test-output-stream {{{
38905 #?     (write 2 "^")
38906 #?     (write-stream 2 _test-output-stream)
38907 #?     (write 2 "$\n")
38908 #?     (rewind-stream _test-output-stream)
38909 #?     # }}}
38910     # check output
38911     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare %ecx 0x34/imm32" "F - test-compare-reg-with-literal")
38912     # . epilogue
38913     89/<- %esp 5/r32/ebp
38914     5d/pop-to-ebp
38915     c3/return
38917 test-emit-subx-stmt-function-call:
38918     # Call a function on a variable on the stack.
38919     #   f foo
38920     # =>
38921     #   (f *(ebp-8))
38922     # (Changing the function name supports overloading in general, but here it
38923     # just serves to help disambiguate things.)
38924     #
38925     # There's a variable on the var stack as follows:
38926     #   name: 'foo'
38927     #   type: int
38928     #   stack-offset: -8
38929     #
38930     # There's nothing in primitives.
38931     #
38932     # We don't perform any checking here on the type of 'f'.
38933     #
38934     # . prologue
38935     55/push-ebp
38936     89/<- %ebp 4/r32/esp
38937     # setup
38938     (clear-stream _test-output-stream)
38939     (clear-stream $_test-output-buffered-file->buffer)
38940 $test-emit-subx-function-call:initialize-type:
38941     # var type/ecx: (payload type-tree) = int
38942     68/push 0/imm32/right:null
38943     68/push 0/imm32/right:null
38944     68/push 0/imm32/left:unused
38945     68/push 1/imm32/value:int
38946     68/push 1/imm32/is-atom?:true
38947     68/push 0x11/imm32/alloc-id:fake:payload
38948     89/<- %ecx 4/r32/esp
38949 $test-emit-subx-function-call:initialize-var:
38950     # var var-foo/ecx: (payload var) = var(type)
38951     68/push 0/imm32/no-register
38952     68/push 0/imm32/no-register
38953     68/push -8/imm32/stack-offset
38954     68/push 1/imm32/block-depth
38955     51/push-ecx/type
38956     68/push 0x11/imm32/alloc-id:fake
38957     68/push 0/imm32/name
38958     68/push 0/imm32/name
38959     68/push 0x11/imm32/alloc-id:fake:payload
38960     89/<- %ecx 4/r32/esp
38961 $test-emit-subx-function-call:initialize-var-name:
38962     # var-foo->name = "foo"
38963     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
38964     (copy-array Heap "foo" %eax)
38965 $test-emit-subx-function-call:initialize-stmt-var:
38966     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
38967     68/push 0/imm32/is-deref:false
38968     68/push 0/imm32/next
38969     68/push 0/imm32/next
38970     51/push-ecx/var-foo
38971     68/push 0x11/imm32/alloc-id:fake
38972     68/push 0x11/imm32/alloc-id:fake:payload
38973     89/<- %ebx 4/r32/esp
38974 $test-emit-subx-function-call:initialize-stmt:
38975     # var stmt/esi: (addr statement)
38976     68/push 0/imm32/no-outputs
38977     68/push 0/imm32/no-outputs
38978     53/push-ebx/inouts
38979     68/push 0x11/imm32/alloc-id:fake
38980     68/push 0/imm32/operation
38981     68/push 0/imm32/operation
38982     68/push 1/imm32/tag
38983     89/<- %esi 4/r32/esp
38984 $test-emit-subx-function-call:initialize-stmt-operation:
38985     # stmt->operation = "f"
38986     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
38987     (copy-array Heap "f" %eax)
38988     # convert
38989     c7 0/subop/copy *Curr-block-depth 0/imm32
38990     (emit-subx-stmt _test-output-buffered-file %esi 0 0 Stderr 0)
38991     (flush _test-output-buffered-file)
38992 #?     # dump _test-output-stream {{{
38993 #?     (write 2 "^")
38994 #?     (write-stream 2 _test-output-stream)
38995 #?     (write 2 "$\n")
38996 #?     (rewind-stream _test-output-stream)
38997 #?     # }}}
38998     # check output
38999     (check-next-stream-line-equal _test-output-stream "(f *(ebp+0xfffffff8))" "F - test-emit-subx-stmt-function-call")
39000     # . epilogue
39001     89/<- %esp 5/r32/ebp
39002     5d/pop-to-ebp
39003     c3/return
39005 test-emit-subx-stmt-function-call-with-literal-arg:
39006     # Call a function on a literal.
39007     #   f 0x34
39008     # =>
39009     #   (f2 0x34)
39010     #
39011     # . prologue
39012     55/push-ebp
39013     89/<- %ebp 4/r32/esp
39014     # setup
39015     (clear-stream _test-output-stream)
39016     (clear-stream $_test-output-buffered-file->buffer)
39017 $test-emit-subx-function-call-with-literal-arg:initialize-type:
39018     # var type/ecx: (payload type-tree) = int
39019     68/push 0/imm32/right:null
39020     68/push 0/imm32/right:null
39021     68/push 0/imm32/left:unused
39022     68/push 0/imm32/value:literal
39023     68/push 1/imm32/is-atom?:true
39024     68/push 0x11/imm32/alloc-id:fake:payload
39025     89/<- %ecx 4/r32/esp
39026 $test-emit-subx-function-call-with-literal-arg:initialize-var:
39027     # var var-foo/ecx: (payload var) = var(lit)
39028     68/push 0/imm32/no-register
39029     68/push 0/imm32/no-register
39030     68/push 0/imm32/no-stack-offset
39031     68/push 1/imm32/block-depth
39032     51/push-ecx/type
39033     68/push 0x11/imm32/alloc-id:fake
39034     68/push 0/imm32/name
39035     68/push 0/imm32/name
39036     68/push 0x11/imm32/alloc-id:fake:payload
39037     89/<- %ecx 4/r32/esp
39038 $test-emit-subx-function-call-with-literal-arg:initialize-var-name:
39039     # var-foo->name = "0x34"
39040     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
39041     (copy-array Heap "0x34" %eax)
39042 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-var:
39043     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
39044     68/push 0/imm32/is-deref:false
39045     68/push 0/imm32/next
39046     68/push 0/imm32/next
39047     51/push-ecx/var-foo
39048     68/push 0x11/imm32/alloc-id:fake
39049     68/push 0x11/imm32/alloc-id:fake:payload
39050     89/<- %ebx 4/r32/esp
39051 $test-emit-subx-function-call-with-literal-arg:initialize-stmt:
39052     # var stmt/esi: (addr statement)
39053     68/push 0/imm32/no-outputs
39054     68/push 0/imm32/no-outputs
39055     53/push-ebx/inouts
39056     68/push 0x11/imm32/alloc-id:fake
39057     68/push 0/imm32/operation
39058     68/push 0/imm32/operation
39059     68/push 1/imm32/tag
39060     89/<- %esi 4/r32/esp
39061 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-operation:
39062     # stmt->operation = "f"
39063     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
39064     (copy-array Heap "f" %eax)
39065     # convert
39066     c7 0/subop/copy *Curr-block-depth 0/imm32
39067     (emit-subx-stmt _test-output-buffered-file %esi 0 %ebx 0 Stderr 0)
39068     (flush _test-output-buffered-file)
39069 #?     # dump _test-output-stream {{{
39070 #?     (write 2 "^")
39071 #?     (write-stream 2 _test-output-stream)
39072 #?     (write 2 "$\n")
39073 #?     (rewind-stream _test-output-stream)
39074 #?     # }}}
39075     # check output
39076     (check-next-stream-line-equal _test-output-stream "(f 0x34)" "F - test-emit-subx-stmt-function-call-with-literal-arg")
39077     # . epilogue
39078     89/<- %esp 5/r32/ebp
39079     5d/pop-to-ebp
39080     c3/return
39082 emit-indent:  # out: (addr buffered-file), n: int
39083     # . prologue
39084     55/push-ebp
39085     89/<- %ebp 4/r32/esp
39086     # . save registers
39087     50/push-eax
39088     # var i/eax: int = n
39089     8b/-> *(ebp+0xc) 0/r32/eax
39090     {
39091       # if (i <= 0) break
39092       3d/compare-eax-with 0/imm32
39093       7e/jump-if-<= break/disp8
39094       (write-buffered *(ebp+8) "  ")
39095       48/decrement-eax
39096       eb/jump loop/disp8
39097     }
39098 $emit-indent:end:
39099     # . restore registers
39100     58/pop-to-eax
39101     # . epilogue
39102     89/<- %esp 5/r32/ebp
39103     5d/pop-to-ebp
39104     c3/return
39106 emit-subx-prologue:  # out: (addr buffered-file)
39107     # . prologue
39108     55/push-ebp
39109     89/<- %ebp 4/r32/esp
39110     #
39111     (write-buffered *(ebp+8) "  # . prologue\n")
39112     (write-buffered *(ebp+8) "  55/push-ebp\n")
39113     (write-buffered *(ebp+8) "  89/<- %ebp 4/r32/esp\n")
39114 $emit-subx-prologue:end:
39115     # . epilogue
39116     89/<- %esp 5/r32/ebp
39117     5d/pop-to-ebp
39118     c3/return
39120 emit-subx-epilogue:  # out: (addr buffered-file)
39121     # . prologue
39122     55/push-ebp
39123     89/<- %ebp 4/r32/esp
39124     #
39125     (write-buffered *(ebp+8) "  # . epilogue\n")
39126     (write-buffered *(ebp+8) "  89/<- %esp 5/r32/ebp\n")
39127     (write-buffered *(ebp+8) "  5d/pop-to-ebp\n")
39128     (write-buffered *(ebp+8) "  c3/return\n")
39129 $emit-subx-epilogue:end:
39130     # . epilogue
39131     89/<- %esp 5/r32/ebp
39132     5d/pop-to-ebp
39133     c3/return