diff options
Diffstat (limited to 'linux/mu.subx')
-rw-r--r-- | linux/mu.subx | 38350 |
1 files changed, 38350 insertions, 0 deletions
diff --git a/linux/mu.subx b/linux/mu.subx new file mode 100644 index 00000000..fa3bda75 --- /dev/null +++ b/linux/mu.subx @@ -0,0 +1,38350 @@ +# The Mu computer's level-2 language, also called Mu. +# http://akkartik.name/post/mu-2019-2 +# +# To run: +# $ ./translate_subx init.linux [0-9]*.subx apps/mu.subx +# $ ./a.elf < prog.mu > prog.elf + +# == Goals +# 1. Be memory safe. It should be impossible to corrupt the heap, or to create +# a bad pointer. (Requires strong type safety.) +# 2. Do as little as possible to achieve goal 1. The translator should be +# implementable in machine code. +# - minimize impedance mismatch between source language and SubX target +# (e.g. programmer manages registers manually) +# - checks over syntax +# (e.g. programmer's register allocation is checked) +# - runtime checks to avoid complex static analysis +# (e.g. array indexing always checks bounds) + +# == Language description +# A program is a sequence of function and type definitions. +# +# Function example: +# fn foo n: int -> _/eax: int { +# ... +# } +# +# Functions consist of a name, optional inputs, optional outputs and a block. +# +# Function inputs and outputs are variables. All variables have a type and +# storage specifier. They can be placed either in memory (on the stack) or in +# one of 6 named registers. +# eax ecx edx ebx esi edi +# Variables in registers must be primitive 32-bit types. +# Variables not explicitly placed in a register are on the stack. +# +# Function inputs are always passed in memory (on the stack), while outputs +# are always returned in registers. Outputs can't be named; they use the +# dummy value '_'. +# +# Blocks mostly consist of statements. +# +# Statements mostly consist of a name, optional inputs and optional outputs. +# +# Statement inputs are variables or literals. Variables need to specify type +# (and storage) the first time they're mentioned but not later. +# +# Statement outputs, like function outputs, must be variables in registers. +# +# Statement names must be either primitives or user-defined functions. +# +# Primitives can write to any register. +# User-defined functions only write to hard-coded registers. Outputs of each +# call must have the same registers as in the function definition. +# +# There are some other statement types: +# - blocks. Multiple statements surrounded by '{...}' and optionally +# prefixed with a label name and ':' +# - { +# ... +# } +# - foo: { +# ... +# } +# +# - variable definitions on the stack. E.g.: +# - var foo: int +# - var bar: (array int 3) +# There's no initializer; variables are automatically initialized. +# The type of a local variable is either word-length (4 bytes) or starts with 'ref'. +# +# - variables definitions in a register. E.g.: +# - var foo/eax: int <- add bar 1 +# The initializer is mandatory and must be a valid instruction that writes +# a single output to the right register. In practice registers will +# usually be either initialized by primitives or copied from eax. +# - var eax: int <- foo bar quux +# var floo/ecx: int <- copy eax +# +# Still todo: +# global variables +# union types +# +# Formal types: +# A program is a linked list of functions +# A function contains: +# name: (handle array byte) +# inouts: linked list of vars <-- 'inouts' is more precise than 'inputs' +# data: (handle var) +# next: (handle list) +# outputs: linked list of vars +# data: (handle var) +# next: (handle list) +# body: (handle block) +# A var-type contains: +# name: (handle array byte) +# type: (handle type-tree) +# +# A statement can be: +# tag 0: a block +# tag 1: a simple statement (stmt1) +# tag 2: a variable defined on the stack +# tag 3: a variable defined in a register +# +# A block contains: +# tag: 0 +# statements: (handle list stmt) +# name: (handle array byte) -- starting with '$' +# +# A regular statement contains: +# tag: 1 +# operation: (handle array byte) +# inouts: (handle list operand) +# outputs: (handle list var) +# +# A variable defined on the stack contains: +# tag: 2 +# name: (handle array byte) +# type: (handle type-tree) +# +# A variable defined in a register contains: +# tag: 3 +# name: (handle array byte) +# type: (handle type-tree) +# reg: (handle array byte) + +# == Translation: managing the stack +# Now that we know what the language looks like in the large, let's think +# about how translation happens from the bottom up. One crucial piece of the +# puzzle is how Mu will clean up variables defined on the stack for you. +# +# Assume that we maintain a 'functions' list while parsing source code. And a +# 'primitives' list is a global constant. Both these contain enough information +# to perform type-checking on function calls or primitive statements, respectively. +# +# Defining variables pushes them on a stack with the current block depth and +# enough information about their location (stack offset or register). +# Starting a block increments the current block id. +# Each statement now has enough information to emit code for it. +# Ending a block is where the magic happens: +# pop all variables at the current block depth +# emit code to restore all register variables introduced at the current depth +# emit code to clean up all stack variables at the current depth (just increment esp) +# decrement the current block depth +# +# Formal types: +# live-vars: stack of vars +# var: +# name: (handle array byte) +# type: (handle type-tree) +# block: int +# stack-offset: int (added to ebp) +# register: (handle array byte) +# either usual register names +# or '*' to indicate any register +# At most one of stack-offset or register-index must be non-zero. +# A register of '*' designates a variable _template_. Only legal in formal +# parameters for primitives. + +# == Translating a single function call +# This one's easy. Assuming we've already checked things, we just drop the +# outputs (which use hard-coded registers) and emit inputs in a standard format. +# +# out1, out2, out3, ... <- name inout1, inout2, inout3, ... +# => +# (name inout1 inout2 inout3) +# +# Formal types: +# functions: linked list of info +# name: (handle array byte) +# inouts: linked list of vars +# outputs: linked list of vars +# body: block (linked list of statements) + +# == Translating a single primitive instruction +# A second crucial piece of the puzzle is how Mu converts fairly regular +# primitives with their uniform syntax to SubX instructions with their gnarly +# x86 details. +# +# Mu instructions have inputs and outputs. Primitives can have up to 2 of +# them. +# SubX instructions have rm32 and r32 operands. +# The translation between them covers almost all the possibilities. +# Instructions with 1 inout may turn into ones with 1 rm32 +# (e.g. incrementing a var on the stack) +# Instructions with 1 output may turn into ones with 1 rm32 +# (e.g. incrementing a var in a register) +# 1 inout and 1 output may turn into 1 rm32 and 1 r32 +# (e.g. adding a var to a reg) +# 2 inouts may turn into 1 rm32 and 1 r32 +# (e.g. adding a reg to a var) +# 1 inout and 1 literal may turn into 1 rm32 and 1 imm32 +# (e.g. adding a constant to a var) +# 1 output and 1 literal may turn into 1 rm32 and 1 imm32 +# (e.g. adding a constant to a reg) +# 2 outputs to hardcoded registers and 1 inout may turn into 1 rm32 +# (special-case: divide edx:eax by a var or reg) +# Observations: +# We always emit rm32. It may be the first inout or the first output. +# We may emit r32 or imm32 or neither. +# When we emit r32 it may come from first inout or second inout or first output. +# +# Accordingly, the formal data structure for a primitive looks like this: +# primitives: linked list of info +# name: (handle array byte) +# mu-inouts: linked list of vars to check +# mu-outputs: linked list of vars to check; at most a singleton +# subx-name: (handle array byte) +# subx-rm32: enum arg-location +# subx-r32: enum arg-location +# subx-imm32: enum arg-location +# subx-imm8: enum arg-location +# subx-disp32: enum arg-location +# subx-xm32: enum arg-location +# subx-x32: enum arg-location +# arg-location: enum +# 0 means none +# 1 means first inout +# 2 means second inout +# 3 means first output + +# == Translating a block +# Emit block name if necessary +# Emit '{' +# When you encounter a statement, emit it as above +# When you encounter a variable declaration +# emit any code needed for it (bzeros) +# push it on the var stack +# update register dict if necessary +# When you encounter '}' +# While popping variables off the var stack until block id changes +# Emit code needed to clean up the stack +# either increment esp +# or pop into appropriate register + +# The rest is straightforward. + +== data + +Program: +_Program-functions: # (handle function) + 0/imm32 +_Program-functions->payload: + 0/imm32 +_Program-types: # (handle typeinfo) + 0/imm32 +_Program-types->payload: + 0/imm32 +_Program-signatures: # (handle function) + 0/imm32 +_Program-signatures->payload: + 0/imm32 + +# Some constants for simulating the data structures described above. +# Many constants here come with a type in a comment. +# +# Sometimes the type is of the value at that offset for the given type. For +# example, if you start at a function record and move forward Function-inouts +# bytes, you'll find a (handle list var). +# +# At other times, the type is of the constant itself. For example, the type of +# the constant Function-size is (addr int). To get the size of a function, +# look in *Function-size. + +Function-name: # (handle array byte) + 0/imm32 +Function-inouts: # (handle list var) + 8/imm32 +Function-outputs: # (handle list var) + 0x10/imm32 +Function-body: # (handle block) + 0x18/imm32 +Function-next: # (handle function) + 0x20/imm32 +Function-size: # (addr int) + 0x28/imm32/40 + +Primitive-name: # (handle array byte) + 0/imm32 +Primitive-inouts: # (handle list var) + 8/imm32 +Primitive-outputs: # (handle list var) + 0x10/imm32 +Primitive-subx-name: # (handle array byte) + 0x18/imm32 +Primitive-subx-rm32: # enum arg-location + 0x20/imm32 +Primitive-subx-r32: # enum arg-location + 0x24/imm32 +Primitive-subx-imm32: # enum arg-location + 0x28/imm32 +Primitive-subx-imm8: # enum arg-location -- only for bit shifts + 0x2c/imm32 +Primitive-subx-disp32: # enum arg-location -- only for branches + 0x30/imm32 +Primitive-subx-xm32: # enum arg-location + 0x34/imm32 +Primitive-subx-x32: # enum arg-location + 0x38/imm32 +Primitive-next: # (handle function) + 0x3c/imm32 +Primitive-size: # (addr int) + 0x44/imm32/68 + +Stmt-tag: # int + 0/imm32 + +Block-stmts: # (handle list stmt) + 4/imm32 +Block-var: # (handle var) + 0xc/imm32 + +Stmt1-operation: # (handle array byte) + 4/imm32 +Stmt1-inouts: # (handle stmt-var) + 0xc/imm32 +Stmt1-outputs: # (handle stmt-var) + 0x14/imm32 + +Vardef-var: # (handle var) + 4/imm32 + +Regvardef-operation: # (handle array byte) + 4/imm32 +Regvardef-inouts: # (handle stmt-var) + 0xc/imm32 +Regvardef-outputs: # (handle stmt-var) # will have exactly one element + 0x14/imm32 + +Stmt-size: # (addr int) + 0x1c/imm32 + +Var-name: # (handle array byte) + 0/imm32 +Var-type: # (handle type-tree) + 8/imm32 +Var-block-depth: # int -- not available until code-generation time + 0x10/imm32 +Var-offset: # int -- not available until code-generation time + 0x14/imm32 +Var-register: # (handle array byte) -- name of a register + 0x18/imm32 +Var-size: # (addr int) + 0x20/imm32 + +List-value: # (handle _) + 0/imm32 +List-next: # (handle list _) + 8/imm32 +List-size: # (addr int) + 0x10/imm32 + +# A stmt-var is like a list of vars with call-site specific metadata +Stmt-var-value: # (handle var) + 0/imm32 +Stmt-var-next: # (handle stmt-var) + 8/imm32 +Stmt-var-is-deref: # boolean + 0x10/imm32 +Stmt-var-size: # (addr int) + 0x14/imm32 + +# A live-var is a var augmented with information needed for tracking live +# variables. +Live-var-value: # (handle var) + 0/imm32 +Live-var-register-spilled: # boolean; only used if value is in a register, and only during code-gen + 8/imm32 +Live-var-size: # (addr int) + 0xc/imm32 + +# Types are expressed as trees (s-expressions) of type-ids (ints). + +Type-tree-is-atom: # boolean + 0/imm32 +# if is-atom? +Type-tree-value: # type-id + 4/imm32 +Type-tree-value-size: # int (for static data structure sizes) + 8/imm32 +Type-tree-parameter-name: # (handle array byte) for type parameters + 8/imm32 +# unless is-atom? +Type-tree-left: # (addr type-tree) + 4/imm32 +Type-tree-right: # (addr type-tree) + 0xc/imm32 +# +Type-tree-size: # (addr int) + 0x14/imm32 + +# Types + +# TODO: Turn this data structure into valid Mu, with (fake) handles rather than addrs. +Type-id: # (stream (addr array byte)) + 0/imm32/write # initialized later from Primitive-type-ids + 0/imm32/read + 0x100/imm32/size + # data + 0/imm32 # 0 reserved for literals; value is just the name + # Not to be used directly, so we don't include a name here. + "int"/imm32 # 1 + "addr"/imm32 # 2 + "array"/imm32 # 3 + "handle"/imm32 # 4 + "boolean"/imm32 # 5 + 0/imm32 # 6 reserved for constants; they're like literals, but value is an int in Var-offset + # Not to be used directly, so we don't include a name here. + "offset"/imm32 # 7: (offset T) is guaranteed to be a 32-bit multiple of size-of(T) + # 0x20 + "byte"/imm32 # 8 + 0/imm32 # 9 reserved for array-capacity; value is in Type-tree-size. + # Not to be used directly, so we don't include a name here. + 0/imm32 # 10 reserved for type parameters; value is (address array byte) in Type-tree-value2. + # Not to be used directly, so we don't include a name here. + "stream"/imm32 # 11 + "slice"/imm32 # 12 + "code-point"/imm32 # 13; smallest scannable unit from a text stream + "grapheme"/imm32 # 14; smallest printable unit; will eventually be composed of multiple code-points, but currently corresponds 1:1 + # only 4-byte graphemes in utf-8 are currently supported; + # unclear how we should deal with larger clusters. + "float"/imm32 # 15 + # 0x40 + 0/imm32 # 16 reserved for literal strings; value is just the name + # Not to be used directly, so we don't include a name here. + # TODO: move this up next to literal ints + # Keep Primitive-type-ids in sync if you add types here. + 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 + 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 + 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 + 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 + 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 + 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 + +Primitive-type-ids: # (addr int) + 0x44 + +# == Type definitions +# Program->types contains some typeinfo for each type definition. +# Types contain vars with types, but can't specify registers. +Typeinfo-id: # type-id + 0/imm32 +Typeinfo-fields: # (handle table (handle array byte) (handle typeinfo-entry)) + 4/imm32 +# Total size must be >= 0 +# During parsing it may take on two additional values: +# -2: not yet initialized +# -1: in process of being computed +# See populate-mu-type-sizes for details. +Typeinfo-total-size-in-bytes: # int + 0xc/imm32 +Typeinfo-next: # (handle typeinfo) + 0x10/imm32 +Typeinfo-size: # (addr int) + 0x18/imm32 + +# Each entry in the typeinfo->fields table has a pointer to a string and a +# pointer to a typeinfo-entry. +Typeinfo-fields-row-size: # (addr int) + 0x10/imm32 + +# typeinfo-entry objects have information about a field in a single record type +# +# each field of a type is represented using two var's: +# 1. the input var: expected type of the field; convenient for creating using parse-var-with-type +# 2. the output var: a constant containing the byte offset; convenient for code-generation +# computing the output happens after parsing; in the meantime we preserve the +# order of fields in the 'index' field. +Typeinfo-entry-input-var: # (handle var) + 0/imm32 +Typeinfo-entry-index: # int + 8/imm32 +Typeinfo-entry-output-var: # (handle var) + 0xc/imm32 +Typeinfo-entry-size: # (addr int) + 0x14/imm32 + +== code + +Entry: + # . prologue + 89/<- %ebp 4/r32/esp + (new-segment *Heap-size Heap) + # if (argv[1] == "test') run-tests() + { + # if (argc <= 1) break + 81 7/subop/compare *ebp 1/imm32 + 7e/jump-if-<= break/disp8 + # if (argv[1] != "test") break + (kernel-string-equal? *(ebp+8) "test") # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + # + (run-tests) + # syscall(exit, *Num-test-failures) + 8b/-> *Num-test-failures 3/r32/ebx + eb/jump $mu-main:end/disp8 + } + # otherwise convert Stdin + (convert-mu Stdin Stdout Stderr 0) + (flush Stdout) + # syscall(exit, 0) + bb/copy-to-ebx 0/imm32 +$mu-main:end: + e8/call syscall_exit/disp32 + +convert-mu: # in: (addr buffered-file), out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + # initialize global data structures + c7 0/subop/copy *Next-block-index 1/imm32 + 8b/-> *Primitive-type-ids 0/r32/eax + 89/<- *Type-id 0/r32/eax # stream-write + c7 0/subop/copy *_Program-functions 0/imm32 + c7 0/subop/copy *_Program-functions->payload 0/imm32 + c7 0/subop/copy *_Program-types 0/imm32 + c7 0/subop/copy *_Program-types->payload 0/imm32 + c7 0/subop/copy *_Program-signatures 0/imm32 + c7 0/subop/copy *_Program-signatures->payload 0/imm32 + # + (parse-mu *(ebp+8) *(ebp+0x10) *(ebp+0x14)) + (populate-mu-type-sizes *(ebp+0x10) *(ebp+0x14)) +#? (dump-typeinfos "=== typeinfos\n") + (check-mu-types *(ebp+0x10) *(ebp+0x14)) + (emit-subx *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) +$convert-mu:end: + # . restore registers + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-empty-input: + # empty input => empty output + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) + (check-stream-equal _test-output-stream "" "F - test-convert-empty-input") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-skeleton: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-skeleton/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-skeleton/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-skeleton/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-skeleton/3") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-skeleton/4") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-skeleton/5") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-skeleton/6") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-skeleton/7") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-multiple-function-skeletons: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream "}\n") + (write _test-input-stream "fn bar {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check first function + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-multiple-function-skeletons/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-multiple-function-skeletons/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-multiple-function-skeletons/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-multiple-function-skeletons/3") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-multiple-function-skeletons/4") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-multiple-function-skeletons/5") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-multiple-function-skeletons/6") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-multiple-function-skeletons/7") + # check second function + (check-next-stream-line-equal _test-output-stream "bar:" "F - test-convert-multiple-function-skeletons/10") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-multiple-function-skeletons/11") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-multiple-function-skeletons/12") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-multiple-function-skeletons/13") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-multiple-function-skeletons/14") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-multiple-function-skeletons/15") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-multiple-function-skeletons/16") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-multiple-function-skeletons/17") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-arg: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo n: int {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-arg/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-arg/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-arg/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-arg/3") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-arg/4") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-arg/5") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-arg/6") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-arg/7") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-function-with-redefined-name: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream "}\n") + (write _test-input-stream "fn foo {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-function-with-redefined-name: output should be empty") + (check-next-stream-line-equal _test-error-stream "fn foo defined more than once" "F - test-function-with-redefined-name: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-function-with-redefined-name: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-function-with-redefined-name-2: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream "}\n") + (write _test-input-stream "sig foo\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-function-with-redefined-name-2: output should be empty") + (check-next-stream-line-equal _test-error-stream "fn foo defined more than once" "F - test-function-with-redefined-name-2: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-function-with-redefined-name-2: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-function-with-redefined-name-3: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "sig foo\n") + (write _test-input-stream "fn foo {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-function-with-redefined-name-3: output should be empty") + (check-next-stream-line-equal _test-error-stream "fn foo defined more than once" "F - test-function-with-redefined-name-3: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-function-with-redefined-name-3: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-function-with-inout-in-register: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo x/eax: int {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-function-with-inout-in-register: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-function-with-inout-in-register: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-function-with-addr-output: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo -> _/eax: (addr int) {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-function-with-addr-output: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-function-with-addr-output: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-function-with-addr-inout: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo a: (addr addr int) {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-function-with-addr-inout: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-function-with-addr-inout: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-function-with-addr-inout-2: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo a: (addr array addr int) {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-function-with-addr-inout-2: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-function-with-addr-inout-2: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-function-with-addr-inout-3: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo a: (addr array (addr int) 3) {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-function-with-addr-inout-3: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-function-with-addr-inout-3: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-function-with-addr-inout-4: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo a: (array (addr int) 3) {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-function-with-addr-inout-4: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-function-with-addr-inout-4: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +# 'main' is an exception +test-function-main-with-addr-inout: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn main a: (addr addr int) {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) + # no errors + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# 'lookup' is an exception, but only in signatures +test-signature-lookup-with-addr-inout: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "sig lookup h: (handle _T) -> _/eax: (addr _T)\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) + # no errors + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-arg-and-body: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo n: int {\n") + (write _test-input-stream " increment n\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-arg-and-body/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-arg-and-body/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-arg-and-body/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-arg-and-body/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-arg-and-body/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-arg-and-body/5") + (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0x00000008)" "F - test-convert-function-with-arg-and-body/6") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-arg-and-body/7") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-arg-and-body/8") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-arg-and-body/9") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-arg-and-body/10") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-arg-and-body/11") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-arg-and-body/12") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-distinguishes-args: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo a: int, b: int {\n") + (write _test-input-stream " increment b\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-distinguishes-args/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-distinguishes-args/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-distinguishes-args/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-distinguishes-args/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-distinguishes-args/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-distinguishes-args/5") + (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0x0000000c)" "F - test-convert-function-distinguishes-args/6") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-distinguishes-args/7") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-distinguishes-args/8") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-distinguishes-args/9") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-distinguishes-args/10") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-distinguishes-args/11") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-distinguishes-args/12") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-return-literal: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo -> _/eax: int {\n") + (write _test-input-stream " return 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-return-literal/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-return-literal/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-return-literal/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-return-literal/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-return-literal/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-return-literal/5") + (check-next-stream-line-equal _test-output-stream " c7 0/subop/copy %eax 0/imm32" "F - test-convert-function-with-return-literal/6") + (check-next-stream-line-equal _test-output-stream " e9/jump $foo:0x00000001:break/disp32" "F - test-convert-function-with-return-literal/7") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-return-literal/8") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-return-literal/9") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-return-literal/10") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-return-literal/11") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-return-literal/12") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-return-literal/13") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-return: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo -> _/eax: int {\n") + (write _test-input-stream " var y: int\n") + (write _test-input-stream " return y\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-return/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-return/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-return/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-return/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-return/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-return/5") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-return/6") # y + (check-next-stream-line-equal _test-output-stream " 8b/-> *(ebp+0xfffffffc) 0x00000000/r32" "F - test-convert-function-with-return/7") + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-return/8") + (check-next-stream-line-equal _test-output-stream " e9/jump $foo:0x00000001:break/disp32" "F - test-convert-function-with-return/9") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-return/10") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-return/11") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-return/12") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-return/13") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-return/14") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-return/15") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-return-float: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo -> _/xmm0: float {\n") + (write _test-input-stream " var y: float\n") + (write _test-input-stream " return y\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-return/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-return/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-return/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-return/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-return/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-return/5") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-return/6") # y + (check-next-stream-line-equal _test-output-stream " f3 0f 10/-> *(ebp+0xfffffffc) 0x00000000/x32" "F - test-convert-function-with-return/7") + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-return/8") + (check-next-stream-line-equal _test-output-stream " e9/jump $foo:0x00000001:break/disp32" "F - test-convert-function-with-return/9") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-return/10") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-return/11") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-return/12") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-return/13") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-return/14") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-return/15") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-return-register: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo -> _/eax: int {\n") + (write _test-input-stream " var y/eax: int <- copy 3\n") + (write _test-input-stream " return y\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-return-register/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-return-register/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-return-register/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-return-register/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-return-register/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-return-register/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-function-with-return-register/6") + (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 3/imm32" "F - test-convert-function-with-return-register/7") + (check-next-stream-line-equal _test-output-stream " 8b/-> %eax 0x00000000/r32" "F - test-convert-function-with-return-register/8") + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 4/imm32" "F - test-convert-function-with-return-register/9") + (check-next-stream-line-equal _test-output-stream " e9/jump $foo:0x00000001:break/disp32" "F - test-convert-function-with-return-register/10") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-return-register/11") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-return-register/12") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-return-register/13") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-return-register/14") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-return-register/15") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-return-register/16") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-function-with-output-without-register: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo -> _: int {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-function-with-output-without-register: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-function-with-output-without-register: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-function-with-outputs-in-conflicting-registers: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo -> _/eax: int, _/eax: int {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-function-with-outputs-in-conflicting-registers: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-function-with-outputs-in-conflicting-registers: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-function-with-named-output: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo -> x/eax: int {\n") + (write _test-input-stream " return 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-function-with-named-output: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-function-with-named-output: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-return-with-wrong-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo -> _/eax: int {\n") + (write _test-input-stream " var x/eax: boolean <- copy 0\n") + (write _test-input-stream " return x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-return-with-wrong-type: output should be empty") + (check-next-stream-line-equal _test-error-stream "fn foo: return: 'x' has the wrong type" "F - test-return-with-wrong-type: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-return-with-wrong-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-missing-return: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo -> _/eax: int {\n") + (write _test-input-stream " var x/eax: boolean <- copy 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-missing-return: output should be empty") + (check-next-stream-line-equal _test-error-stream "fn foo: final statement should be a 'return'" "F - test-missing-return: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-missing-return: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-missing-return-2: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo -> _/eax: int {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-missing-return-2: output should be empty") + (check-next-stream-line-equal _test-error-stream "fn foo: final statement should be a 'return'" "F - test-missing-return-2: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-missing-return-2: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-early-exit-without-return: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo -> _/eax: int {\n") + (write _test-input-stream " break\n") + (write _test-input-stream " return 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-early-exit-without-return: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-early-exit-without-return: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-return-with-too-few-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo -> _/eax: int {\n") + (write _test-input-stream " return\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-return-with-too-few-inouts: output should be empty") + (check-next-stream-line-equal _test-error-stream "fn foo: return: too few inouts" "F - test-return-with-too-few-inouts: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-return-with-too-few-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-return-with-too-many-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo -> _/eax: int {\n") + (write _test-input-stream " return 0, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-return-with-too-many-inouts: output should be empty") + (check-next-stream-line-equal _test-error-stream "fn foo: return: too many inouts" "F - test-return-with-too-many-inouts: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-return-with-too-many-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-return-unavailable-value: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo -> _/eax: int, _/ecx: int {\n") + (write _test-input-stream " var x/eax: int <- copy 0\n") + (write _test-input-stream " var y/ecx: int <- copy 0\n") + (write _test-input-stream " return y, x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-return-unavailable-value: output should be empty") + (check-next-stream-line-equal _test-error-stream "fn foo: return: 'x' is no longer available" "F - test-return-unavailable-value: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-return-unavailable-value: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-return-literal-to-float: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo -> _/xmm0: float {\n") + (write _test-input-stream " return 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-return-literal-to-float: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-return-literal-to-float: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-return-with-duplicate-values: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo -> _/eax: int, _/ecx: int {\n") + (write _test-input-stream " var x/eax: int <- copy 0x34\n") + (write _test-input-stream " return x, x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-return-with-duplicate-values/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-return-with-duplicate-values/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-return-with-duplicate-values/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-return-with-duplicate-values/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-return-with-duplicate-values/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-return-with-duplicate-values/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-return-with-duplicate-values/6") + (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0x34/imm32" "F - test-convert-return-with-duplicate-values/7") + (check-next-stream-line-equal _test-output-stream " 8b/-> %eax 0x00000000/r32" "F - test-convert-return-with-duplicate-values/8") + (check-next-stream-line-equal _test-output-stream " 8b/-> %eax 0x00000001/r32" "F - test-convert-return-with-duplicate-values/9") + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 4/imm32" "F - test-convert-return-with-duplicate-values/10") + (check-next-stream-line-equal _test-output-stream " e9/jump $foo:0x00000001:break/disp32" "F - test-convert-return-with-duplicate-values/11") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-return-with-duplicate-values/12") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-return-with-duplicate-values/13") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-return-with-duplicate-values/14") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-return-with-duplicate-values/15") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-return-with-duplicate-values/16") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-return-with-duplicate-values/17") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-return-with-duplicate-values-2: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo -> _/eax: int, _/ecx: int {\n") + (write _test-input-stream " var x/ecx: int <- copy 0x34\n") + (write _test-input-stream " return x, x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-return-with-duplicate-values-2/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-return-with-duplicate-values-2/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-return-with-duplicate-values-2/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-return-with-duplicate-values-2/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-return-with-duplicate-values-2/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-return-with-duplicate-values-2/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-return-with-duplicate-values-2/6") + (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 0x34/imm32" "F - test-convert-return-with-duplicate-values-2/7") + (check-next-stream-line-equal _test-output-stream " 8b/-> %ecx 0x00000000/r32" "F - test-convert-return-with-duplicate-values-2/8") + (check-next-stream-line-equal _test-output-stream " 8b/-> %ecx 0x00000001/r32" "F - test-convert-return-with-duplicate-values-2/9") + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 4/imm32" "F - test-convert-return-with-duplicate-values-2/10") + (check-next-stream-line-equal _test-output-stream " e9/jump $foo:0x00000001:break/disp32" "F - test-convert-return-with-duplicate-values-2/11") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-return-with-duplicate-values-2/12") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-return-with-duplicate-values-2/13") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-return-with-duplicate-values-2/14") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-return-with-duplicate-values-2/15") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-return-with-duplicate-values-2/16") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-return-with-duplicate-values-2/17") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-stmt-with-unknown-var: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " x <- copy 0x34\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-stmt-with-unknown-var: output should be empty") + (check-next-stream-line-equal _test-error-stream "fn foo: unknown variable 'x'" "F - test-stmt-with-unknown-var: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-stmt-with-unknown-var: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-stmt-with-invalid-identifier: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " 1 <- copy 0x34\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-stmt-with-invalid-identifier: output should be empty") + (check-next-stream-line-equal _test-error-stream "fn foo: invalid identifier '1'" "F - test-stmt-with-invalid-identifier: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-stmt-with-invalid-identifier: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-stmt-with-deref-var: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " *x <- copy 0x34\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-stmt-with-deref-var: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-stmt-with-deref-var: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-function-with-literal-arg: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo a: int, b: int -> _/eax: int {\n") + (write _test-input-stream " var result/eax: int <- copy a\n") + (write _test-input-stream " result <- add 1\n") + (write _test-input-stream " return result\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-literal-arg/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-literal-arg/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-literal-arg/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-literal-arg/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-literal-arg/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-literal-arg/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-function-with-literal-arg/6") + (check-next-stream-line-equal _test-output-stream " 8b/-> *(ebp+0x00000008) 0x00000000/r32" "F - test-convert-function-with-literal-arg/7") + (check-next-stream-line-equal _test-output-stream " 05/add-to-eax 1/imm32" "F - test-convert-function-with-literal-arg/8") + (check-next-stream-line-equal _test-output-stream " 8b/-> %eax 0x00000000/r32" "F - test-convert-function-with-literal-arg/9") + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 4/imm32" "F - test-convert-function-with-literal-arg/10") + (check-next-stream-line-equal _test-output-stream " e9/jump $foo:0x00000001:break/disp32" "F - test-convert-function-with-literal-arg/11") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-literal-arg/12") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-literal-arg/13") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-literal-arg/14") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-literal-arg/15") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-literal-arg/16") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-literal-arg/17") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-literal-arg-2: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo a: int, b: int -> _/ebx: int {\n") + (write _test-input-stream " var result/ebx: int <- copy a\n") + (write _test-input-stream " result <- add 1\n") + (write _test-input-stream " return result\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-literal-arg-2/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-literal-arg-2/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-literal-arg-2/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-literal-arg-2/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-literal-arg-2/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-literal-arg-2/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ebx" "F - test-convert-function-with-literal-arg-2/6") + (check-next-stream-line-equal _test-output-stream " 8b/-> *(ebp+0x00000008) 0x00000003/r32" "F - test-convert-function-with-literal-arg-2/7") + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %ebx 1/imm32" "F - test-convert-function-with-literal-arg-2/8") + (check-next-stream-line-equal _test-output-stream " 8b/-> %ebx 0x00000003/r32" "F - test-convert-function-with-literal-arg-2/9") + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 4/imm32" "F - test-convert-function-with-literal-arg-2/10") + (check-next-stream-line-equal _test-output-stream " e9/jump $foo:0x00000001:break/disp32" "F - test-convert-function-with-literal-arg-2/11") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-literal-arg-2/12") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-literal-arg-2/13") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-literal-arg-2/14") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-literal-arg-2/15") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-literal-arg-2/16") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-literal-arg-2/17") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-call-with-literal-arg: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn main -> _/ebx: int {\n") + (write _test-input-stream " var result/eax: int <- do-add 3 4\n") + (write _test-input-stream " return result\n") + (write _test-input-stream "}\n") + (write _test-input-stream "fn do-add a: int, b: int -> _/eax: int {\n") + (write _test-input-stream " var result/eax: int <- copy a\n") + (write _test-input-stream " result <- add b\n") + (write _test-input-stream " return result\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "main:" "F - test-convert-function-call-with-literal-arg/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-literal-arg/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call-with-literal-arg/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-literal-arg/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-call-with-literal-arg/4") + (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:" "F - test-convert-function-call-with-literal-arg/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-function-call-with-literal-arg/6") + (check-next-stream-line-equal _test-output-stream " (do-add 3 4)" "F - test-convert-function-call-with-literal-arg/7") + (check-next-stream-line-equal _test-output-stream " 8b/-> %eax 0x00000003/r32" "F - test-convert-function-call-with-literal-arg/8") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-function-with-local-var-in-reg/9") + (check-next-stream-line-equal _test-output-stream " e9/jump $main:0x00000001:break/disp32" "F - test-convert-function-call-with-literal-arg/10") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-call-with-literal-arg/11") + (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-literal-arg/12") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-literal-arg/13") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-literal-arg/14") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-literal-arg/15") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-literal-arg/16") + (check-next-stream-line-equal _test-output-stream "do-add:" "F - test-convert-function-call-with-literal-arg/17") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-literal-arg/18") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call-with-literal-arg/19") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-literal-arg/20") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-call-with-literal-arg/21") + (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:loop:" "F - test-convert-function-call-with-literal-arg/22") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-function-call-with-literal-arg/23") + (check-next-stream-line-equal _test-output-stream " 8b/-> *(ebp+0x00000008) 0x00000000/r32" "F - test-convert-function-call-with-literal-arg/24") + (check-next-stream-line-equal _test-output-stream " 03/add *(ebp+0x0000000c) 0x00000000/r32" "F - test-convert-function-call-with-literal-arg/25") + (check-next-stream-line-equal _test-output-stream " 8b/-> %eax 0x00000000/r32" "F - test-convert-function-call-with-literal-arg/26") + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 4/imm32" "F - test-convert-function-call-with-literal-arg/27") + (check-next-stream-line-equal _test-output-stream " e9/jump $do-add:0x00000002:break/disp32" "F - test-convert-function-call-with-literal-arg/28") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-call-with-literal-arg/29") + (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:break:" "F - test-convert-function-call-with-literal-arg/30") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-literal-arg/31") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-literal-arg/32") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-literal-arg/33") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-literal-arg/34") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-call-with-literal-string-arg: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " string-func \"abc\"\n") + (write _test-input-stream "}\n") + (write _test-input-stream "sig string-func in: (addr array byte)\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + # no errors + # not bothering checking output + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-call-with-null-addr: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " bar 0\n") + (write _test-input-stream "}\n") + (write _test-input-stream "sig bar in: (addr int)\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + # no errors + # not bothering checking output + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-call-with-signature: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn main -> _/ebx: int {\n") + (write _test-input-stream " var result/eax: int <- do-add 3 4\n") + (write _test-input-stream " return result\n") + (write _test-input-stream "}\n") + (write _test-input-stream "sig do-add a: int, b: int -> _/eax: int\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "main:" "F - test-convert-function-call-with-signature/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-signature/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call-with-signature/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-signature/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-call-with-signature/4") + (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:" "F - test-convert-function-call-with-signature/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-function-call-with-literal-arg/6") + (check-next-stream-line-equal _test-output-stream " (do-add 3 4)" "F - test-convert-function-call-with-signature/6") + (check-next-stream-line-equal _test-output-stream " 8b/-> %eax 0x00000003/r32" "F - test-convert-function-call-with-literal-arg/8") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-function-with-local-var-in-reg/9") + (check-next-stream-line-equal _test-output-stream " e9/jump $main:0x00000001:break/disp32" "F - test-convert-function-call-with-literal-arg/10") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-call-with-signature/7") + (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-signature/8") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-signature/9") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-signature/10") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-signature/11") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-signature/12") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-local-var-in-mem: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: int\n") + (write _test-input-stream " increment x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-var-in-mem/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-var-in-mem/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-var-in-mem/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-local-var-in-mem/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-in-mem/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-var-in-mem/5") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-local-var-in-mem/6") + (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0xfffffffc)" "F - test-convert-function-with-local-var-in-mem/7") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-in-mem/9") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-var-in-mem/10") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-var-in-mem/11") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-local-var-in-mem/12") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-local-var-in-mem/13") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-var-in-mem/14") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-invalid-literal: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " increment 1n\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-convert-invalid-literal: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-convert-invalid-literal: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-valid-literal-with-metadata: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: int <- copy 1/abc\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # no errors + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-local-var-in-mem-has-no-initializer: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: int <- copy 0\n") + (write _test-input-stream " increment x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-var-in-mem-has-no-initializer: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-var-in-mem-has-no-initializer: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-function-with-local-var-with-compound-type-in-mem: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: (addr int)\n") + (write _test-input-stream " copy-to x, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-var-with-compound-type-in-mem/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-var-with-compound-type-in-mem/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-var-with-compound-type-in-mem/2") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-with-compound-type-in-mem/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-var-with-compound-type-in-mem/5") + (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") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-with-compound-type-in-mem/9") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-var-with-compound-type-in-mem/10") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-var-with-compound-type-in-mem/11") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-var-with-compound-type-in-mem/14") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-local-var-in-reg: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/ecx: int <- copy 3\n") + (write _test-input-stream " x <- increment\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-var-in-reg/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-var-in-reg/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-var-in-reg/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-local-var-in-reg/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-in-reg/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-var-in-reg/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-function-with-local-var-in-reg/6") + (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-convert-function-with-local-var-in-reg/7") + (check-next-stream-line-equal _test-output-stream " 41/increment-ecx" "F - test-convert-function-with-local-var-in-reg/8") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-in-reg/9") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-in-reg/10") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-var-in-reg/11") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-var-in-reg/12") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-local-var-in-reg/13") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-local-var-in-reg/14") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-var-in-reg/15") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-local-var-in-same-reg: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/ecx: int <- copy 3\n") + (write _test-input-stream " var y/ecx: int <- copy x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-var-in-same-reg/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-var-in-same-reg/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-var-in-same-reg/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-local-var-in-same-reg/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-in-same-reg/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-var-in-same-reg/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-function-with-local-var-in-same-reg/6") + (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") + # optimization: skip the second copy + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-in-same-reg/8") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-in-same-reg/9") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-var-in-same-reg/10") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-var-in-same-reg/11") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-local-var-in-same-reg/12") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-local-var-in-same-reg/13") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-var-in-same-reg/14") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-local-var-in-same-reg-dereferenced: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/ecx: (addr int) <- copy 0\n") + (write _test-input-stream " var y/ecx: int <- copy *x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-var-in-same-reg-dereferenced/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-var-in-same-reg-dereferenced/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-var-in-same-reg-dereferenced/2") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-in-same-reg-dereferenced/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-var-in-same-reg-dereferenced/5") + (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") + (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") + (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 + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-in-same-reg-dereferenced/10") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-var-in-same-reg-dereferenced/11") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-var-in-same-reg-dereferenced/12") + (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") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-local-var-in-same-reg-dereferenced/14") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-var-in-same-reg-dereferenced/15") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-float-var-in-wrong-register: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: int <- copy 0\n") + (write _test-input-stream " var y/eax: float <- convert x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-float-var-in-wrong-register: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-float-var-in-wrong-register: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-non-float-var-in-wrong-register: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/xmm5: int <- copy 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-non-float-var-in-wrong-register: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-non-float-var-in-wrong-register: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-function-with-allocate: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/ecx: (addr handle int) <- copy 0\n") + (write _test-input-stream " allocate x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-allocate/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-allocate/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-allocate/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-allocate/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-allocate/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-allocate/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-function-with-allocate/6") + (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 0/imm32" "F - test-convert-function-with-allocate/7") + (check-next-stream-line-equal _test-output-stream " (allocate Heap 0x00000004 %ecx)" "F - test-convert-function-with-allocate/8") # 4 = size-of(int) + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-function-with-allocate/9") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-allocate/10") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-allocate/11") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-allocate/12") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-allocate/13") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-allocate/14") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-allocate/15") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-initializer-in-hex: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/ecx: int <- copy 10\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-initializer-in-hex: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-initializer-in-hex: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-function-with-second-local-var-in-same-reg: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/ecx: int <- copy 3\n") + (write _test-input-stream " var y/ecx: int <- copy 4\n") + (write _test-input-stream " y <- increment\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-second-local-var-in-same-reg/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-second-local-var-in-same-reg/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-second-local-var-in-same-reg/2") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-second-local-var-in-same-reg/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-second-local-var-in-same-reg/5") + (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") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " 41/increment-ecx" "F - test-convert-function-with-second-local-var-in-same-reg/9") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-second-local-var-in-same-reg/11") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-second-local-var-in-same-reg/12") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-second-local-var-in-same-reg/13") + (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") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-second-local-var-in-same-reg/15") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-second-local-var-in-same-reg/16") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-read-clobbered-reg-var: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) # bytes of args in call to convert-mu + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/ecx: int <- copy 3\n") + (write _test-input-stream " var y/ecx: int <- copy 4\n") + (write _test-input-stream " x <- increment\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-read-clobbered-reg-var: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-read-clobbered-reg-var: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-overlapping-int-fp-registers: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) # bytes of args in call to convert-mu + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: int <- copy 3\n") + (write _test-input-stream " var y/xmm0: float <- convert x\n") + (write _test-input-stream " x <- increment\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # no errors + (check-next-stream-line-equal _test-error-stream "" "F - test-overlapping-int-fp-registers: error message") + # don't bother checking the generated code + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-function-call: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn main -> _/ebx: int {\n") + (write _test-input-stream " var result/ebx: int <- foo\n") + (write _test-input-stream " return result\n") + (write _test-input-stream "}\n") + (write _test-input-stream "fn foo -> _/ebx: int {\n") + (write _test-input-stream " var result/ebx: int <- copy 3\n") + (write _test-input-stream " return result\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "main:" "F - test-convert-function-call/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-call/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-call/4") + (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:" "F - test-convert-function-call/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ebx" "F - test-convert-function-call-with-literal-arg/6") + (check-next-stream-line-equal _test-output-stream " (foo)" "F - test-convert-function-call/6") + (check-next-stream-line-equal _test-output-stream " 8b/-> %ebx 0x00000003/r32" "F - test-convert-function-call-with-literal-arg/8") + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 4/imm32" "F - test-convert-function-call-with-literal-arg/27") + (check-next-stream-line-equal _test-output-stream " e9/jump $main:0x00000001:break/disp32" "F - test-convert-function-call-with-literal-arg/10") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-call/7") + (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call/8") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call/9") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-call/10") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call/11") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call/12") + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-call/13") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call/14") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call/15") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-call/16") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-call/17") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-call/18") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ebx" "F - test-convert-function-call-with-literal-arg/6") + (check-next-stream-line-equal _test-output-stream " bb/copy-to-ebx 3/imm32" "F - test-convert-function-call/19") + (check-next-stream-line-equal _test-output-stream " 8b/-> %ebx 0x00000003/r32" "F - test-convert-function-call-with-literal-arg/8") + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 4/imm32" "F - test-convert-function-call-with-literal-arg/27") + (check-next-stream-line-equal _test-output-stream " e9/jump $foo:0x00000002:break/disp32" "F - test-convert-function-call-with-literal-arg/10") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-call/20") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-call/21") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call/22") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-call/23") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call/24") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call/25") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-call-with-inout-with-compound-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn f {\n") + (write _test-input-stream " var x: (addr int)\n") + (write _test-input-stream " g x\n") + (write _test-input-stream "}\n") + (write _test-input-stream "fn g a: (addr int) {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "f:" "F - test-convert-function-call-with-inout-with-compound-type/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-inout-with-compound-type/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call-with-inout-with-compound-type/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-inout-with-compound-type/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-call-with-inout-with-compound-type/4") + (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:" "F - test-convert-function-call-with-inout-with-compound-type/5") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-call-with-inout-with-compound-type/6") + (check-next-stream-line-equal _test-output-stream " (g *(ebp+0xfffffffc))" "F - test-convert-function-call-with-inout-with-compound-type/7") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-call-with-inout-with-compound-type/9") + (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:" "F - test-convert-function-call-with-inout-with-compound-type/10") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-inout-with-compound-type/11") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-inout-with-compound-type/12") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-inout-with-compound-type/13") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-inout-with-compound-type/14") + (check-next-stream-line-equal _test-output-stream "g:" "F - test-convert-function-call-with-inout-with-compound-type/15") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-inout-with-compound-type/16") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call-with-inout-with-compound-type/17") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-inout-with-compound-type/18") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-inout-with-compound-type/19") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-inout-with-compound-type/20") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-inout-with-compound-type/21") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-inout-with-compound-type/22") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-call-with-inout-with-type-parameter: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn f {\n") + (write _test-input-stream " var x: (addr int)\n") + (write _test-input-stream " g x\n") + (write _test-input-stream "}\n") + (write _test-input-stream "fn g a: (addr _) {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # no error; types matched + (check-stream-equal _test-error-stream "" "F - test-convert-function-call-with-inout-with-type-parameter: error stream should be empty") + # don't bother checking the generated code; that's in the test 'test-local-clobbered-by-fn-output' below + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-function-call-with-incorrect-inout-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn f {\n") + (write _test-input-stream " var x: int\n") + (write _test-input-stream " g x\n") + (write _test-input-stream "}\n") + (write _test-input-stream "fn g a: foo {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-convert-function-call-with-incorrect-inout-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-inout-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + 5d/pop-to-ebp + c3/return + +test-convert-function-call-with-inout-with-incorrect-compound-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn f {\n") + (write _test-input-stream " var x: (addr int)\n") + (write _test-input-stream " g x\n") + (write _test-input-stream "}\n") + (write _test-input-stream "fn g a: (addr bool) {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-convert-function-call-with-inout-with-incorrect-compound-type: output should be empty") + (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") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-function-call-with-inout-with-multiple-type-parameters: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn f {\n") + (write _test-input-stream " var x: (addr int)\n") + (write _test-input-stream " var y: (addr int)\n") + (write _test-input-stream " g x, y\n") + (write _test-input-stream "}\n") + (write _test-input-stream "fn g a: (addr _), b: (addr _) {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # no errors + (check-stream-equal _test-error-stream "" "F - test-convert-function-call-with-inout-with-multiple-type-parameters: error stream should be empty") + # don't bother checking the generated code + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-type-parameter-matches-rest-of-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn f {\n") + (write _test-input-stream " var x: (addr array int)\n") + (write _test-input-stream " g x\n") + (write _test-input-stream "}\n") + (write _test-input-stream "fn g a: (addr _) {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # no errors + (check-stream-equal _test-error-stream "" "F - test-type-parameter-matches-rest-of-type: error stream should be empty") + # don't bother checking the generated code + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-function-call-with-inout-with-incompatible-type-parameters: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn f {\n") + (write _test-input-stream " var x: (addr int)\n") + (write _test-input-stream " var y: (addr boolean)\n") + (write _test-input-stream " g x, y\n") + (write _test-input-stream "}\n") + (write _test-input-stream "fn g a: (addr _T), b: (addr _T) {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-convert-function-call-with-inout-with-incompatible-type-parameters: output should be empty") + (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") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-function-call-with-too-few-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn f {\n") + (write _test-input-stream " g\n") + (write _test-input-stream "}\n") + (write _test-input-stream "fn g a: int {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-convert-function-call-with-too-few-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-few-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + 5d/pop-to-ebp + c3/return + +test-convert-function-call-with-too-many-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn f {\n") + (write _test-input-stream " var x: int\n") + (write _test-input-stream " g x\n") + (write _test-input-stream "}\n") + (write _test-input-stream "fn g {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-convert-function-call-with-too-many-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-many-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + 5d/pop-to-ebp + c3/return + +test-convert-function-call-with-incorrect-output-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn f {\n") + (write _test-input-stream " var x/eax: int <- g\n") + (write _test-input-stream "}\n") + (write _test-input-stream "fn g -> _/eax: foo {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-convert-function-call-with-incorrect-output-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-output-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + 5d/pop-to-ebp + c3/return + +test-convert-function-call-with-too-few-outputs: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn f {\n") + (write _test-input-stream " g\n") + (write _test-input-stream "}\n") + (write _test-input-stream "fn g -> _/eax: int {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-convert-function-call-with-too-few-outputs: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-few-outputs: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + 5d/pop-to-ebp + c3/return + +test-convert-function-call-with-too-many-outputs: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn f {\n") + (write _test-input-stream " var x/eax: int <- g\n") + (write _test-input-stream "}\n") + (write _test-input-stream "fn g {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-convert-function-call-with-too-many-outputs: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-many-outputs: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + 5d/pop-to-ebp + c3/return + +test-convert-function-call-with-missing-output-register: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn f {\n") + (write _test-input-stream " var x: int\n") + (write _test-input-stream " x <- g\n") + (write _test-input-stream "}\n") + (write _test-input-stream "fn g -> _/eax: int {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-convert-function-call-with-missing-output-register: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-missing-output-register: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + 5d/pop-to-ebp + c3/return + +test-convert-function-call-with-incorrect-output-register: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn f {\n") + (write _test-input-stream " var x/ecx: int <- g\n") + (write _test-input-stream "}\n") + (write _test-input-stream "fn g -> _/eax: int {\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-convert-function-call-with-incorrect-output-register: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-output-register: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + 5d/pop-to-ebp + c3/return + +test-convert-function-with-local-var-dereferenced: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/ecx: (addr int) <- copy 0\n") + (write _test-input-stream " increment *x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-var-dereferenced/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-var-dereferenced/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-var-dereferenced/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-local-var-dereferenced/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-dereferenced/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-var-dereferenced/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-function-with-local-var-dereferenced/6") + (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 0/imm32" "F - test-convert-function-with-local-var-dereferenced/7") + (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *ecx" "F - test-convert-function-with-local-var-dereferenced/8") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-dereferenced/9") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-dereferenced/10") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-var-dereferenced/11") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-var-dereferenced/12") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-local-var-dereferenced/13") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-local-var-dereferenced/14") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-var-dereferenced/15") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-dereference-of-var-on-stack: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: (addr int)\n") + (write _test-input-stream " increment *x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-dereference-of-var-on-stack: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-dereference-of-var-on-stack: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-function-with-byte-operations: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: byte <- copy 0\n") + (write _test-input-stream " var y/ecx: byte <- copy 0\n") + (write _test-input-stream " y <- copy-byte x\n") + (write _test-input-stream " var z/edx: (addr byte) <- copy 0\n") + (write _test-input-stream " y <- copy-byte *z\n") + (write _test-input-stream " copy-byte-to *z, x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-byte-operations/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-byte-operations/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-byte-operations/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-byte-operations/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-byte-operations/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-byte-operations/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-function-with-byte-operations/6") + (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-function-with-byte-operations/7") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-function-with-byte-operations/8") + (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 0/imm32" "F - test-convert-function-with-byte-operations/9") + (check-next-stream-line-equal _test-output-stream " 8a/byte-> %eax 0x00000001/r32" "F - test-convert-function-with-byte-operations/10") + (check-next-stream-line-equal _test-output-stream " 81 4/subop/and %ecx 0xff/imm32" "F - test-convert-function-with-byte-operations/11") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %edx" "F - test-convert-function-with-byte-operations/12") + (check-next-stream-line-equal _test-output-stream " ba/copy-to-edx 0/imm32" "F - test-convert-function-with-byte-operations/13") + (check-next-stream-line-equal _test-output-stream " 8a/byte-> *edx 0x00000001/r32" "F - test-convert-function-with-byte-operations/14") + (check-next-stream-line-equal _test-output-stream " 81 4/subop/and %ecx 0xff/imm32" "F - test-convert-function-with-byte-operations/15") + (check-next-stream-line-equal _test-output-stream " 88/byte<- *edx 0x00000000/r32" "F - test-convert-function-with-byte-operations/16") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %edx" "F - test-convert-function-with-byte-operations/17") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-function-with-byte-operations/18") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-function-with-byte-operations/19") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-byte-operations/20") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-byte-operations/21") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-byte-operations/22") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-byte-operations/23") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-byte-operations/24") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-byte-operations/25") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# variables of type 'byte' are not allowed on the stack +test-byte-values-on-stack: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: byte\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-byte-values-on-stack: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-byte-values-on-stack: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +# variables of type 'byte' are not allowed in esi or edi +test-byte-values-in-unsupported-registers: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/esi: byte <- copy 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-byte-values-in-unsupported-registers: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-byte-values-in-unsupported-registers: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +# variables of type 'byte' _can_ be function args. They then occupy 4 bytes. +test-copy-byte-var-from-fn-arg: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo x: byte, y: int {\n") + (write _test-input-stream " var a/eax: byte <- copy x\n") + (write _test-input-stream " var b/eax: int <- copy y\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-copy-byte-from-fn-arg/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-copy-byte-from-fn-arg/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-copy-byte-from-fn-arg/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-copy-byte-from-fn-arg/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-copy-byte-from-fn-arg/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-copy-byte-from-fn-arg/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-copy-byte-from-fn-arg/6") + (check-next-stream-line-equal _test-output-stream " 8b/-> *(ebp+0x00000008) 0x00000000/r32" "F - test-copy-byte-from-fn-arg/7") + (check-next-stream-line-equal _test-output-stream " 8b/-> *(ebp+0x0000000c) 0x00000000/r32" "F - test-copy-byte-from-fn-arg/8") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-copy-byte-from-fn-arg/9") + (check-next-stream-line-equal _test-output-stream " }" "F - test-copy-byte-from-fn-arg/10") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-copy-byte-from-fn-arg/11") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-copy-byte-from-fn-arg/12") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-copy-byte-from-fn-arg/13") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-copy-byte-from-fn-arg/14") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-copy-byte-from-fn-arg/15") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-compare-register-with-literal: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/ecx: int <- copy 0\n") + (write _test-input-stream " compare x, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-compare-register-with-literal/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-compare-register-with-literal/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-compare-register-with-literal/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-compare-register-with-literal/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-compare-register-with-literal/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-compare-register-with-literal/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-compare-register-with-literal/6") + (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 0/imm32" "F - test-convert-compare-register-with-literal/7") + (check-next-stream-line-equal _test-output-stream " 81 7/subop/compare %ecx 0/imm32" "F - test-convert-compare-register-with-literal/8") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-compare-register-with-literal/10") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-compare-register-with-literal/11") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-compare-register-with-literal/12") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-compare-register-with-literal/13") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-compare-register-with-literal/14") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-compare-register-with-literal/15") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-compare-byte-with-literal: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/ecx: byte <- copy 0\n") + (write _test-input-stream " compare x, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # no errors; output is identical to test-convert-compare-register-with-literal + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-unknown-variable: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " compare x, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-unknown-variable: output should be empty") + (check-next-stream-line-equal _test-error-stream "fn foo: unknown variable 'x'" "F - test-unknown-variable: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-unknown-variable: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-function-with-local-var-in-block: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " {\n") + (write _test-input-stream " var x: int\n") + (write _test-input-stream " increment x\n") + (write _test-input-stream " }\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-var-in-block/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-var-in-block/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-var-in-block/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-local-var-in-block/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-in-block/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-var-in-block/5") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-in-block/6") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-local-var-in-block/7") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-local-var-in-block/8") + (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0xfffffffc)" "F - test-convert-function-with-local-var-in-block/9") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-in-block/11") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-local-var-in-block/12") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-in-block/13") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-var-in-block/14") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-var-in-block/15") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-local-var-in-block/16") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-local-var-in-block/17") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-var-in-block/18") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-local-var-in-mem-after-block: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " {\n") + (write _test-input-stream " var y: int\n") + (write _test-input-stream " }\n") + (write _test-input-stream " var x: int\n") + (write _test-input-stream " increment x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-var-in-mem-after-block/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-var-in-mem-after-block/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-var-in-mem-after-block/2") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-in-mem-after-block/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-var-in-mem-after-block/5") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-in-mem-after-block/6") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-local-var-in-mem-after-block/7") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-local-var-in-mem-after-block/8") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-in-mem-after-block/10") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-local-var-in-mem-after-block/11") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-local-var-in-mem-after-block/12") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-in-mem-after-block/15") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-var-in-mem-after-block/16") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-var-in-mem-after-block/17") + (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") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-local-var-in-mem-after-block/19") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-var-in-mem-after-block/20") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-local-var-in-named-block: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " $bar: {\n") + (write _test-input-stream " var x: int\n") + (write _test-input-stream " increment x\n") + (write _test-input-stream " }\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-var-in-named-block/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-var-in-named-block/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-var-in-named-block/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-local-var-in-named-block/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-in-named-block/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-var-in-named-block/5") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-in-named-block/6") + (check-next-stream-line-equal _test-output-stream "$bar:loop:" "F - test-convert-function-with-local-var-in-named-block/7") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-local-var-in-named-block/8") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-in-named-block/11") + (check-next-stream-line-equal _test-output-stream "$bar:break:" "F - test-convert-function-with-local-var-in-named-block/12") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-in-named-block/13") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-var-in-named-block/14") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-var-in-named-block/15") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-local-var-in-named-block/16") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-local-var-in-named-block/17") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-var-in-named-block/18") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-unknown-variable-in-named-block: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " $a: {\n") + (write _test-input-stream " compare x, 0\n") + (write _test-input-stream " }\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-unknown-variable-in-named-block: output should be empty") + (check-next-stream-line-equal _test-error-stream "fn foo: unknown variable 'x'" "F - test-unknown-variable-in-named-block: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-unknown-variable-in-named-block: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-always-shadow-outermost-reg-vars-in-function: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/ecx: int <- copy 3\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-always-shadow-outermost-reg-vars-in-function/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-always-shadow-outermost-reg-vars-in-function/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-always-shadow-outermost-reg-vars-in-function/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-always-shadow-outermost-reg-vars-in-function/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-always-shadow-outermost-reg-vars-in-function/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-always-shadow-outermost-reg-vars-in-function/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-compare-register-with-literal/6") + (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-always-shadow-outermost-reg-vars-in-function/8") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9") + (check-next-stream-line-equal _test-output-stream " }" "F - test-always-shadow-outermost-reg-vars-in-function/12") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-always-shadow-outermost-reg-vars-in-function/13") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-always-shadow-outermost-reg-vars-in-function/14") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-always-shadow-outermost-reg-vars-in-function/15") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-always-shadow-outermost-reg-vars-in-function/16") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-always-shadow-outermost-reg-vars-in-function/17") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-shadow-local: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/ecx: int <- copy 3\n") + (write _test-input-stream " {\n") + (write _test-input-stream " var y/ecx: int <- copy 4\n") + (write _test-input-stream " }\n") + (write _test-input-stream " x <- increment\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-shadow-local/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-shadow-local/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-shadow-local/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-shadow-local/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-shadow-local/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-shadow-local/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-shadow-local/6") + (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-shadow-local/7") + (check-next-stream-line-equal _test-output-stream " {" "F - test-shadow-local/8") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-shadow-local/9") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-shadow-local/10") + (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 4/imm32" "F - test-shadow-local/11") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-shadow-local/12") + (check-next-stream-line-equal _test-output-stream " }" "F - test-shadow-local/13") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-shadow-local/14") + (check-next-stream-line-equal _test-output-stream " 41/increment-ecx" "F - test-shadow-local/15") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-shadow-local/16") + (check-next-stream-line-equal _test-output-stream " }" "F - test-shadow-local/17") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-shadow-local/18") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-shadow-local/19") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-shadow-local/20") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-shadow-local/21") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-shadow-local/22") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-shadow-name: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/ecx: int <- copy 3\n") + (write _test-input-stream " {\n") + (write _test-input-stream " var x/edx: int <- copy 4\n") + (write _test-input-stream " }\n") + (write _test-input-stream " x <- increment\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-shadow-name/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-shadow-name/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-shadow-name/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-shadow-name/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-shadow-name/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-shadow-name/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-shadow-name/6") + (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-shadow-name/7") + (check-next-stream-line-equal _test-output-stream " {" "F - test-shadow-name/8") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-shadow-name/9") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %edx" "F - test-shadow-name/10") + (check-next-stream-line-equal _test-output-stream " ba/copy-to-edx 4/imm32" "F - test-shadow-name/11") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %edx" "F - test-shadow-name/12") + (check-next-stream-line-equal _test-output-stream " }" "F - test-shadow-name/13") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-shadow-name/14") + (check-next-stream-line-equal _test-output-stream " 41/increment-ecx" "F - test-shadow-name/15") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-shadow-name/16") + (check-next-stream-line-equal _test-output-stream " }" "F - test-shadow-name/17") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-shadow-name/18") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-shadow-name/19") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-shadow-name/20") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-shadow-name/21") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-shadow-name/22") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-shadow-name-2: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/ecx: int <- copy 3\n") + (write _test-input-stream " {\n") + (write _test-input-stream " var x/edx: int <- copy 4\n") + (write _test-input-stream " var y/ecx: int <- copy 5\n") + (write _test-input-stream " }\n") + (write _test-input-stream " x <- increment\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-shadow-name-2/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-shadow-name-2/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-shadow-name-2/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-shadow-name-2/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-shadow-name-2/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-shadow-name-2/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-shadow-name-2/6") + (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-shadow-name-2/7") + (check-next-stream-line-equal _test-output-stream " {" "F - test-shadow-name-2/8") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-shadow-name-2/9") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %edx" "F - test-shadow-name-2/10") + (check-next-stream-line-equal _test-output-stream " ba/copy-to-edx 4/imm32" "F - test-shadow-name-2/11") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-shadow-name-2/12") + (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 5/imm32" "F - test-shadow-name-2/13") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-shadow-name-2/14") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %edx" "F - test-shadow-name-2/15") + (check-next-stream-line-equal _test-output-stream " }" "F - test-shadow-name-2/16") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-shadow-name-2/17") + (check-next-stream-line-equal _test-output-stream " 41/increment-ecx" "F - test-shadow-name-2/18") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-shadow-name-2/19") + (check-next-stream-line-equal _test-output-stream " }" "F - test-shadow-name-2/20") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-shadow-name-2/21") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-shadow-name-2/22") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-shadow-name-2/23") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-shadow-name-2/24") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-shadow-name-2/25") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-do-not-spill-same-register-in-block: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/ecx: int <- copy 3\n") + (write _test-input-stream " var y/ecx: int <- copy 4\n") + (write _test-input-stream " y <- increment\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-do-not-spill-same-register-in-block/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-do-not-spill-same-register-in-block/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-do-not-spill-same-register-in-block/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-do-not-spill-same-register-in-block/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-do-not-spill-same-register-in-block/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-do-not-spill-same-register-in-block/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-do-not-spill-same-register-in-block/6") + (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-do-not-spill-same-register-in-block/7") + (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 4/imm32" "F - test-do-not-spill-same-register-in-block/8") + (check-next-stream-line-equal _test-output-stream " 41/increment-ecx" "F - test-do-not-spill-same-register-in-block/9") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-do-not-spill-same-register-in-block/10") + (check-next-stream-line-equal _test-output-stream " }" "F - test-do-not-spill-same-register-in-block/11") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-do-not-spill-same-register-in-block/12") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-do-not-spill-same-register-in-block/13") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-do-not-spill-same-register-in-block/14") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-do-not-spill-same-register-in-block/15") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-do-not-spill-same-register-in-block/16") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-spill-different-register-in-block: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: int <- copy 3\n") + (write _test-input-stream " var y/ecx: int <- copy 4\n") + (write _test-input-stream " y <- increment\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-spill-different-register-in-block/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-spill-different-register-in-block/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-spill-different-register-in-block/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-spill-different-register-in-block/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-spill-different-register-in-block/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-spill-different-register-in-block/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-spill-different-register-in-block/6") + (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 3/imm32" "F - test-spill-different-register-in-block/7") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-spill-different-register-in-block/8") + (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 4/imm32" "F - test-spill-different-register-in-block/9") + (check-next-stream-line-equal _test-output-stream " 41/increment-ecx" "F - test-spill-different-register-in-block/10") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-spill-different-register-in-block/11") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-spill-different-register-in-block/12") + (check-next-stream-line-equal _test-output-stream " }" "F - test-spill-different-register-in-block/13") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-spill-different-register-in-block/14") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-spill-different-register-in-block/15") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-spill-different-register-in-block/16") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-spill-different-register-in-block/17") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-spill-different-register-in-block/18") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-branches-in-block: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo x: int {\n") + (write _test-input-stream " {\n") + (write _test-input-stream " break-if->=\n") + (write _test-input-stream " loop-if-addr<\n") + (write _test-input-stream " increment x\n") + (write _test-input-stream " loop\n") + (write _test-input-stream " }\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-branches-in-block/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-branches-in-block/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-branches-in-block/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-branches-in-block/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-in-block/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-branches-in-block/5") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-in-block/6") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-branches-in-block/7") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-in-block/8") + (check-next-stream-line-equal _test-output-stream " 0f 8c/jump-if-< break/disp32" "F - test-convert-function-with-branches-in-block/9") + (check-next-stream-line-equal _test-output-stream " e9/jump $foo:0x00000002:break/disp32" "F - test-convert-function-with-branches-in-block/10") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-in-block/11") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-in-block/12") + (check-next-stream-line-equal _test-output-stream " 0f 83/jump-if-addr>= break/disp32" "F - test-convert-function-with-branches-in-block/13") + (check-next-stream-line-equal _test-output-stream " e9/jump $foo:0x00000002:loop/disp32" "F - test-convert-function-with-branches-in-block/14") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-in-block/15") + (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0x00000008)" "F - test-convert-function-with-branches-in-block/16") + (check-next-stream-line-equal _test-output-stream " e9/jump loop/disp32" "F - test-convert-function-with-branches-in-block/17") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-in-block/18") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-branches-in-block/19") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-in-block/20") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-branches-in-block/21") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-branches-in-block/22") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-branches-in-block/23") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-branches-in-block/24") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-branches-in-block/25") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-branches-in-block-2: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo x: int {\n") + (write _test-input-stream " {\n") + (write _test-input-stream " break-if->=\n") + (write _test-input-stream " loop-if-float<\n") + (write _test-input-stream " increment x\n") + (write _test-input-stream " loop\n") + (write _test-input-stream " }\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-branches-in-block/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-branches-in-block/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-branches-in-block/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-branches-in-block/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-in-block/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-branches-in-block/5") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-in-block/6") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-branches-in-block/7") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-in-block/8") + (check-next-stream-line-equal _test-output-stream " 0f 8c/jump-if-< break/disp32" "F - test-convert-function-with-branches-in-block/9") + (check-next-stream-line-equal _test-output-stream " e9/jump $foo:0x00000002:break/disp32" "F - test-convert-function-with-branches-in-block/10") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-in-block/11") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-in-block/12") + (check-next-stream-line-equal _test-output-stream " 0f 83/jump-if-addr>= break/disp32" "F - test-convert-function-with-branches-in-block/13") + (check-next-stream-line-equal _test-output-stream " e9/jump $foo:0x00000002:loop/disp32" "F - test-convert-function-with-branches-in-block/14") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-in-block/15") + (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0x00000008)" "F - test-convert-function-with-branches-in-block/16") + (check-next-stream-line-equal _test-output-stream " e9/jump loop/disp32" "F - test-convert-function-with-branches-in-block/17") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-in-block/18") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-branches-in-block/19") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-in-block/20") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-branches-in-block/21") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-branches-in-block/22") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-branches-in-block/23") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-branches-in-block/24") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-branches-in-block/25") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-branches-in-named-block: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo x: int {\n") + (write _test-input-stream " $bar: {\n") + (write _test-input-stream " break-if->= $bar\n") + (write _test-input-stream " loop-if-addr< $bar\n") + (write _test-input-stream " increment x\n") + (write _test-input-stream " loop\n") + (write _test-input-stream " }\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-branches-in-named-block/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-branches-in-named-block/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-branches-in-named-block/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-branches-in-named-block/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-in-named-block/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-branches-in-named-block/5") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-in-named-block/6") + (check-next-stream-line-equal _test-output-stream "$bar:loop:" "F - test-convert-function-with-branches-in-named-block/7") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-in-named-block/8") + (check-next-stream-line-equal _test-output-stream " 0f 8c/jump-if-< break/disp32" "F - test-convert-function-with-branches-in-named-block/9") + (check-next-stream-line-equal _test-output-stream " e9/jump $bar:break/disp32" "F - test-convert-function-with-branches-in-named-block/10") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-in-named-block/11") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-in-named-block/12") + (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") + (check-next-stream-line-equal _test-output-stream " e9/jump $bar:loop/disp32" "F - test-convert-function-with-branches-in-named-block/14") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-in-named-block/15") + (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0x00000008)" "F - test-convert-function-with-branches-in-named-block/16") + (check-next-stream-line-equal _test-output-stream " e9/jump loop/disp32" "F - test-convert-function-with-branches-in-named-block/17") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-in-named-block/18") + (check-next-stream-line-equal _test-output-stream "$bar:break:" "F - test-convert-function-with-branches-in-named-block/19") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-in-named-block/20") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-branches-in-named-block/21") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-branches-in-named-block/22") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-branches-in-named-block/23") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-branches-in-named-block/24") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-branches-in-named-block/25") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-var-in-nested-block: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo x: int {\n") + (write _test-input-stream " {\n") + (write _test-input-stream " {\n") + (write _test-input-stream " var x: int\n") + (write _test-input-stream " increment x\n") + (write _test-input-stream " }\n") + (write _test-input-stream " }\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-var-in-nested-block/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-var-in-nested-block/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-var-in-nested-block/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-var-in-nested-block/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-var-in-nested-block/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-var-in-nested-block/5") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-var-in-nested-block/6") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-var-in-nested-block/7") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-var-in-nested-block/8") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:" "F - test-convert-function-with-var-in-nested-block/9") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-var-in-nested-block/10") + (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0xfffffffc)" "F - test-convert-function-with-var-in-nested-block/11") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-var-in-nested-block/13") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:" "F - test-convert-function-with-var-in-nested-block/14") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-var-in-nested-block/15") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-var-in-nested-block/16") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-var-in-nested-block/17") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-var-in-nested-block/18") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-var-in-nested-block/19") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-var-in-nested-block/20") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-var-in-nested-block/21") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-var-in-nested-block/22") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-multiple-vars-in-nested-blocks: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo x: int {\n") + (write _test-input-stream " {\n") + (write _test-input-stream " var x/eax: int <- copy 0\n") + (write _test-input-stream " {\n") + (write _test-input-stream " var y: int\n") + (write _test-input-stream " x <- add y\n") + (write _test-input-stream " }\n") + (write _test-input-stream " }\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-multiple-vars-in-nested-blocks/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-multiple-vars-in-nested-blocks/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-multiple-vars-in-nested-blocks/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-multiple-vars-in-nested-blocks/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-multiple-vars-in-nested-blocks/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-multiple-vars-in-nested-blocks/5") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-multiple-vars-in-nested-blocks/6") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-multiple-vars-in-nested-blocks/7") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-function-with-multiple-vars-in-nested-blocks/8") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-multiple-vars-in-nested-blocks/10") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:" "F - test-convert-function-with-multiple-vars-in-nested-blocks/11") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-multiple-vars-in-nested-blocks/12") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-multiple-vars-in-nested-blocks/15") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:" "F - test-convert-function-with-multiple-vars-in-nested-blocks/16") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-function-with-multiple-vars-in-nested-blocks/17") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-multiple-vars-in-nested-blocks/18") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-multiple-vars-in-nested-blocks/19") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-multiple-vars-in-nested-blocks/20") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-multiple-vars-in-nested-blocks/21") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-multiple-vars-in-nested-blocks/22") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-multiple-vars-in-nested-blocks/23") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-multiple-vars-in-nested-blocks/24") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-multiple-vars-in-nested-blocks/25") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-branches-and-local-vars: + # A conditional 'break' after a 'var' in a block is converted into a + # nested block that performs all necessary cleanup before jumping. This + # results in some ugly code duplication. + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " {\n") + (write _test-input-stream " var x: int\n") + (write _test-input-stream " break-if->=\n") + (write _test-input-stream " increment x\n") + (write _test-input-stream " }\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-branches-and-local-vars/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-branches-and-local-vars/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-branches-and-local-vars/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-branches-and-local-vars/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-and-local-vars/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-branches-and-local-vars/5") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-and-local-vars/6") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-branches-and-local-vars/7") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-branches-and-local-vars/8") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-and-local-vars/9") + (check-next-stream-line-equal _test-output-stream " 0f 8c/jump-if-< break/disp32" "F - test-convert-function-with-branches-and-local-vars/10") + (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") + (check-next-stream-line-equal _test-output-stream " e9/jump $foo:0x00000002:break/disp32" "F - test-convert-function-with-branches-and-local-vars/12") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-and-local-vars/13") + (check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0xfffffffc)" "F - test-convert-function-with-branches-and-local-vars/14") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-and-local-vars/16") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-branches-and-local-vars/17") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-and-local-vars/18") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-branches-and-local-vars/19") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-branches-and-local-vars/20") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-branches-and-local-vars/21") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-branches-and-local-vars/22") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-branches-and-local-vars/23") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-conditional-loops-and-local-vars: + # A conditional 'loop' after a 'var' in a block is converted into a nested + # block that performs all necessary cleanup before jumping. This results + # in some ugly code duplication. + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " {\n") + (write _test-input-stream " var x: int\n") + (write _test-input-stream " loop-if->=\n") + (write _test-input-stream " increment x\n") + (write _test-input-stream " }\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-conditional-loops-and-local-vars/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-conditional-loops-and-local-vars/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-conditional-loops-and-local-vars/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-conditional-loops-and-local-vars/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-conditional-loops-and-local-vars/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-conditional-loops-and-local-vars/5") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-conditional-loops-and-local-vars/6") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-conditional-loops-and-local-vars/7") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-conditional-loops-and-local-vars/8") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-conditional-loops-and-local-vars/9") + (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") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-conditional-loops-and-local-vars/13") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-conditional-loops-and-local-vars/16") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-conditional-loops-and-local-vars/17") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-conditional-loops-and-local-vars/18") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-conditional-loops-and-local-vars/19") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-conditional-loops-and-local-vars/20") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-conditional-loops-and-local-vars/21") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-conditional-loops-and-local-vars/22") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-conditional-loops-and-local-vars/23") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-unconditional-loops-and-local-vars: + # An unconditional 'loop' after a 'var' in a block is emitted _after_ the + # regular block cleanup. Any instructions after 'loop' are dead and + # therefore skipped. + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " {\n") + (write _test-input-stream " var x: int\n") + (write _test-input-stream " loop\n") + (write _test-input-stream " increment x\n") + (write _test-input-stream " }\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-unconditional-loops-and-local-vars/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-unconditional-loops-and-local-vars/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-unconditional-loops-and-local-vars/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-unconditional-loops-and-local-vars/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-unconditional-loops-and-local-vars/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-unconditional-loops-and-local-vars/5") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-unconditional-loops-and-local-vars/6") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-unconditional-loops-and-local-vars/7") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-unconditional-loops-and-local-vars/8") + (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") + (check-next-stream-line-equal _test-output-stream " e9/jump loop/disp32" "F - test-convert-function-with-unconditional-loops-and-local-vars/10") + # not emitted: ff 0/subop/increment *(ebp+0xfffffffc) + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-unconditional-loops-and-local-vars/11") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-unconditional-loops-and-local-vars/12") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-unconditional-loops-and-local-vars/13") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-unconditional-loops-and-local-vars/14") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-unconditional-loops-and-local-vars/15") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-unconditional-loops-and-local-vars/16") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-unconditional-loops-and-local-vars/17") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-unconditional-loops-and-local-vars/18") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-branches-and-loops-and-local-vars: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " {\n") + (write _test-input-stream " var x: int\n") + (write _test-input-stream " break-if->=\n") + (write _test-input-stream " increment x\n") + (write _test-input-stream " loop\n") + (write _test-input-stream " }\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-branches-and-loops-and-local-vars/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-branches-and-loops-and-local-vars/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-branches-and-loops-and-local-vars/2") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-and-loops-and-local-vars/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-branches-and-loops-and-local-vars/5") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-and-loops-and-local-vars/6") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-branches-and-loops-and-local-vars/7") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-branches-and-loops-and-local-vars/8") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-branches-and-loops-and-local-vars/9") + (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") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-and-loops-and-local-vars/13") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " e9/jump loop/disp32" "F - test-convert-function-with-branches-and-loops-and-local-vars/16") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-and-loops-and-local-vars/17") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-branches-and-loops-and-local-vars/18") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-and-loops-and-local-vars/19") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-branches-and-loops-and-local-vars/20") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-branches-and-loops-and-local-vars/21") + (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") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-branches-and-loops-and-local-vars/23") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-branches-and-loops-and-local-vars/24") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-nonlocal-branches-and-loops-and-local-vars: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " a: {\n") + (write _test-input-stream " var x: int\n") + (write _test-input-stream " {\n") + (write _test-input-stream " var y: int\n") + (write _test-input-stream " break-if->= a\n") + (write _test-input-stream " increment x\n") + (write _test-input-stream " loop\n") + (write _test-input-stream " }\n") + (write _test-input-stream " }\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/2") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/5") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/6") + (check-next-stream-line-equal _test-output-stream "a:loop:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/7") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/9") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/10") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/12") + (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") + (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") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/17") + (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") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/21") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/22") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/24") + (check-next-stream-line-equal _test-output-stream "a:break:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/25") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/26") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/27") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/28") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/31") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # non-local conditional branch from a block without a local variable, + # unwinding a local on the stack + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " a: {\n") + (write _test-input-stream " var x: int\n") + (write _test-input-stream " {\n") + (write _test-input-stream " break-if->= a\n") + (write _test-input-stream " }\n") + (write _test-input-stream " }\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/1") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/4") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/6") + (check-next-stream-line-equal _test-output-stream "a:loop:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/7") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/9") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/11") + (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") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/15") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/16") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/19") + (check-next-stream-line-equal _test-output-stream "a:break:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/20") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/21") + (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") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/23") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/26") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # non-local unconditional branch from a block without a local variable, + # unwinding a local on the stack + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " a: {\n") + (write _test-input-stream " var x: int\n") + (write _test-input-stream " {\n") + (write _test-input-stream " break a\n") + (write _test-input-stream " }\n") + (write _test-input-stream " }\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/1") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/4") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/6") + (check-next-stream-line-equal _test-output-stream "a:loop:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/7") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/9") + (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") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/14") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/17") + (check-next-stream-line-equal _test-output-stream "a:break:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/18") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/19") + (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") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/21") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/24") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " a: {\n") + (write _test-input-stream " var x/esi: int <- copy 0\n") + (write _test-input-stream " {\n") + (write _test-input-stream " break a\n") + (write _test-input-stream " }\n") + (write _test-input-stream " }\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/1") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/4") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/6") + (check-next-stream-line-equal _test-output-stream "a:loop:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/7") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/10") + (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") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/14") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/17") + (check-next-stream-line-equal _test-output-stream "a:break:" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/18") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/19") + (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") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/21") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/24") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-nonlocal-unconditional-break-and-local-vars: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " a: {\n") + (write _test-input-stream " var x: int\n") + (write _test-input-stream " {\n") + (write _test-input-stream " var y: int\n") + (write _test-input-stream " break a\n") + (write _test-input-stream " increment x\n") + (write _test-input-stream " }\n") + (write _test-input-stream " }\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/2") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/5") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/6") + (check-next-stream-line-equal _test-output-stream "a:loop:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/7") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/8") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/9") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/10") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/11") + (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") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/15") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/16") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/18") + (check-next-stream-line-equal _test-output-stream "a:break:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/19") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/20") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/21") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/22") + (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") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/24") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/25") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-unconditional-break-and-local-vars: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " {\n") + (write _test-input-stream " var x: int\n") + (write _test-input-stream " {\n") + (write _test-input-stream " var y: int\n") + (write _test-input-stream " break\n") + (write _test-input-stream " increment x\n") + (write _test-input-stream " }\n") + (write _test-input-stream " }\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-unconditional-break-and-local-vars/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-unconditional-break-and-local-vars/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-unconditional-break-and-local-vars/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-unconditional-break-and-local-vars/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-unconditional-break-and-local-vars/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-unconditional-break-and-local-vars/5") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-unconditional-break-and-local-vars/6") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-unconditional-break-and-local-vars/7") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/8") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-unconditional-break-and-local-vars/9") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:" "F - test-convert-function-with-unconditional-break-and-local-vars/10") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/11") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-unconditional-break-and-local-vars/13") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:" "F - test-convert-function-with-unconditional-break-and-local-vars/14") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-unconditional-break-and-local-vars/16") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-unconditional-break-and-local-vars/17") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-unconditional-break-and-local-vars/18") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-unconditional-break-and-local-vars/19") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-unconditional-break-and-local-vars/20") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-unconditional-break-and-local-vars/21") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-unconditional-break-and-local-vars/22") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-unconditional-break-and-local-vars/23") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-nonlocal-unconditional-loop-and-local-vars: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " a: {\n") + (write _test-input-stream " var x: int\n") + (write _test-input-stream " {\n") + (write _test-input-stream " var y: int\n") + (write _test-input-stream " loop a\n") + (write _test-input-stream " increment x\n") + (write _test-input-stream " }\n") + (write _test-input-stream " }\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/2") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/5") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/6") + (check-next-stream-line-equal _test-output-stream "a:loop:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/7") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/8") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/9") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/10") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/11") + (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") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/15") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/16") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/18") + (check-next-stream-line-equal _test-output-stream "a:break:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/19") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/20") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/21") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/22") + (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") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/24") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/25") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-local-array-var-in-mem: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: (array int 3)\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-array-var-in-mem/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-array-var-in-mem/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-array-var-in-mem/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-local-array-var-in-mem/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-array-var-in-mem/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-array-var-in-mem/5") + # define x + (check-next-stream-line-equal _test-output-stream " (push-n-zero-bytes 0x0000000c)" "F - test-convert-function-with-local-array-var-in-mem/7") + (check-next-stream-line-equal _test-output-stream " 68/push 0x0000000c/imm32" "F - test-convert-function-with-local-array-var-in-mem/8") + # reclaim x + (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") + # + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-array-var-in-mem/10") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-array-var-in-mem/11") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-array-var-in-mem/12") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-local-array-var-in-mem/13") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-local-array-var-in-mem/14") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-array-var-in-mem/15") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-array-size-in-hex: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: (array int 10)\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-array-size-in-hex: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-array-size-in-hex: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-array-size-with-metadata: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: (array int 3/bar)\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # no errors + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-populate: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/ecx: (addr handle array int) <- copy 0\n") + (write _test-input-stream " populate x, 7\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-populate/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-populate/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-populate/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-populate/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-populate/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-populate/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-function-with-populate/6") + (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 0/imm32" "F - test-convert-function-with-populate/7") + (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) + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-function-with-populate/9") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-populate/10") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-populate/11") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-populate/12") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-populate/13") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-populate/14") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-populate/15") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# special-case for size(byte) when allocating array +test-convert-function-with-local-array-of-bytes-in-mem: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: (array byte 3)\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-array-of-bytes-in-mem/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-array-of-bytes-in-mem/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-array-of-bytes-in-mem/2") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-array-of-bytes-in-mem/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-array-of-bytes-in-mem/5") + # define x + (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") + (check-next-stream-line-equal _test-output-stream " 68/push 0x00000003/imm32" "F - test-convert-function-with-local-array-of-bytes-in-mem/8") + # reclaim x + (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") + # + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-array-of-bytes-in-mem/10") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-array-of-bytes-in-mem/11") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-array-of-bytes-in-mem/12") + (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") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-local-array-of-bytes-in-mem/14") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-array-of-bytes-in-mem/15") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-address: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: int\n") + (write _test-input-stream " var b/eax: (addr int) <- address a\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-address/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-address/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-address/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-address/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-address/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-address/5") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-address/6") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-address/7") + (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(ebp+0xfffffffc) 0x00000000/r32" "F - test-convert-address/8") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-address/9") + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-address/10") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-address/11") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-address/12") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-address/13") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-address/14") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-address/15") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-address/16") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-floating-point-convert: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a/eax: int <- copy 0\n") + (write _test-input-stream " var b/xmm1: float <- convert a\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-floating-point-convert/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-floating-point-convert/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-floating-point-convert/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-floating-point-convert/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-floating-point-convert/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-floating-point-convert/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-floating-point-convert/6") + (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-floating-point-convert/7") + (check-next-stream-line-equal _test-output-stream " 81 5/subop/subtract %esp 4/imm32" "F - test-convert-floating-point-convert/8") + (check-next-stream-line-equal _test-output-stream " f3 0f 11/<- *esp 1/x32" "F - test-convert-floating-point-convert/9") + (check-next-stream-line-equal _test-output-stream " f3 0f 2a/convert-to-float %eax 0x00000001/x32" "F - test-convert-floating-point-convert/10") + (check-next-stream-line-equal _test-output-stream " f3 0f 10/-> *esp 1/x32" "F - test-convert-floating-point-convert/11") + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 4/imm32" "F - test-floating-point-convert/12") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-floating-point-convert/13") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-floating-point-convert/14") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-floating-point-convert/15") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-floating-point-convert/16") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-floating-point-convert/17") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-floating-point-convert/18") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-floating-point-convert/19") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-floating-point-convert-2: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a/eax: int <- copy 0\n") + (write _test-input-stream " var b/xmm1: float <- convert a\n") + (write _test-input-stream " a <- convert b\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-floating-point-convert-2/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-floating-point-convert-2/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-floating-point-convert-2/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-floating-point-convert-2/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-floating-point-convert-2/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-floating-point-convert-2/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-floating-point-convert-2/6") + (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-floating-point-convert-2/7") + (check-next-stream-line-equal _test-output-stream " 81 5/subop/subtract %esp 4/imm32" "F - test-convert-floating-point-convert-2/8") + (check-next-stream-line-equal _test-output-stream " f3 0f 11/<- *esp 1/x32" "F - test-convert-floating-point-convert-2/9") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " f3 0f 10/-> *esp 1/x32" "F - test-convert-floating-point-convert-2/12") + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 4/imm32" "F - test-floating-point-convert-2/13") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-floating-point-convert-2/14") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-floating-point-convert-2/15") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-floating-point-convert-2/16") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-floating-point-convert-2/17") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-floating-point-convert-2/18") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-floating-point-convert-2/19") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-floating-point-convert-2/20") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-floating-point-operation: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn f {\n") + (write _test-input-stream " var m: float\n") + (write _test-input-stream " var x/xmm1: float <- copy m\n") + (write _test-input-stream " var y/xmm5: float <- copy m\n") + (write _test-input-stream " x <- copy y\n") + (write _test-input-stream " copy-to m, y\n") + (write _test-input-stream " x <- add y\n") + (write _test-input-stream " x <- add m\n") + (write _test-input-stream " x <- subtract y\n") + (write _test-input-stream " x <- subtract m\n") + (write _test-input-stream " x <- multiply y\n") + (write _test-input-stream " x <- multiply m\n") + (write _test-input-stream " x <- divide y\n") + (write _test-input-stream " x <- divide m\n") + (write _test-input-stream " x <- reciprocal y\n") + (write _test-input-stream " x <- reciprocal m\n") + (write _test-input-stream " x <- square-root y\n") + (write _test-input-stream " x <- square-root m\n") + (write _test-input-stream " x <- inverse-square-root y\n") + (write _test-input-stream " x <- inverse-square-root m\n") + (write _test-input-stream " x <- max y\n") + (write _test-input-stream " x <- max m\n") + (write _test-input-stream " x <- min y\n") + (write _test-input-stream " x <- min m\n") + (write _test-input-stream " compare x, y\n") + (write _test-input-stream " compare x, m\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "f:" "F - test-convert-floating-point-operation/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-floating-point-operation/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-floating-point-operation/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-floating-point-operation/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-floating-point-operation/4") + (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:" "F - test-convert-floating-point-operation/5") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-floating-point-operation/6") + (check-next-stream-line-equal _test-output-stream " 81 5/subop/subtract %esp 4/imm32" "F - test-convert-floating-point-operation/7") + (check-next-stream-line-equal _test-output-stream " f3 0f 11/<- *esp 1/x32" "F - test-convert-floating-point-operation/8") + (check-next-stream-line-equal _test-output-stream " f3 0f 10/copy *(ebp+0xfffffffc) 0x00000001/x32" "F - test-convert-floating-point-operation/9") + (check-next-stream-line-equal _test-output-stream " 81 5/subop/subtract %esp 4/imm32" "F - test-convert-floating-point-operation/10") + (check-next-stream-line-equal _test-output-stream " f3 0f 11/<- *esp 5/x32" "F - test-convert-floating-point-operation/11") + (check-next-stream-line-equal _test-output-stream " f3 0f 10/copy *(ebp+0xfffffffc) 0x00000005/x32" "F - test-convert-floating-point-operation/12") + (check-next-stream-line-equal _test-output-stream " f3 0f 11/copy %xmm1 0x00000005/x32" "F - test-convert-floating-point-operation/13") + (check-next-stream-line-equal _test-output-stream " f3 0f 11/copy *(ebp+0xfffffffc) 0x00000005/x32" "F - test-convert-floating-point-operation/14") + (check-next-stream-line-equal _test-output-stream " f3 0f 58/add %xmm5 0x00000001/x32" "F - test-convert-floating-point-operation/15") + (check-next-stream-line-equal _test-output-stream " f3 0f 58/add *(ebp+0xfffffffc) 0x00000001/x32" "F - test-convert-floating-point-operation/16") + (check-next-stream-line-equal _test-output-stream " f3 0f 5c/subtract %xmm5 0x00000001/x32" "F - test-convert-floating-point-operation/17") + (check-next-stream-line-equal _test-output-stream " f3 0f 5c/subtract *(ebp+0xfffffffc) 0x00000001/x32" "F - test-convert-floating-point-operation/18") + (check-next-stream-line-equal _test-output-stream " f3 0f 59/multiply %xmm5 0x00000001/x32" "F - test-convert-floating-point-operation/19") + (check-next-stream-line-equal _test-output-stream " f3 0f 59/multiply *(ebp+0xfffffffc) 0x00000001/x32" "F - test-convert-floating-point-operation/20") + (check-next-stream-line-equal _test-output-stream " f3 0f 5e/divide %xmm5 0x00000001/x32" "F - test-convert-floating-point-operation/21") + (check-next-stream-line-equal _test-output-stream " f3 0f 5e/divide *(ebp+0xfffffffc) 0x00000001/x32" "F - test-convert-floating-point-operation/22") + (check-next-stream-line-equal _test-output-stream " f3 0f 53/reciprocal %xmm5 0x00000001/x32" "F - test-convert-floating-point-operation/23") + (check-next-stream-line-equal _test-output-stream " f3 0f 53/reciprocal *(ebp+0xfffffffc) 0x00000001/x32" "F - test-convert-floating-point-operation/24") + (check-next-stream-line-equal _test-output-stream " f3 0f 51/square-root %xmm5 0x00000001/x32" "F - test-convert-floating-point-operation/25") + (check-next-stream-line-equal _test-output-stream " f3 0f 51/square-root *(ebp+0xfffffffc) 0x00000001/x32" "F - test-convert-floating-point-operation/26") + (check-next-stream-line-equal _test-output-stream " f3 0f 52/inverse-square-root %xmm5 0x00000001/x32" "F - test-convert-floating-point-operation/27") + (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") + (check-next-stream-line-equal _test-output-stream " f3 0f 5f/max %xmm5 0x00000001/x32" "F - test-convert-floating-point-operation/29") + (check-next-stream-line-equal _test-output-stream " f3 0f 5f/max *(ebp+0xfffffffc) 0x00000001/x32" "F - test-convert-floating-point-operation/30") + (check-next-stream-line-equal _test-output-stream " f3 0f 5d/min %xmm5 0x00000001/x32" "F - test-convert-floating-point-operation/31") + (check-next-stream-line-equal _test-output-stream " f3 0f 5d/min *(ebp+0xfffffffc) 0x00000001/x32" "F - test-convert-floating-point-operation/32") + (check-next-stream-line-equal _test-output-stream " 0f 2f/compare %xmm5 0x00000001/x32" "F - test-convert-floating-point-operation/33") + (check-next-stream-line-equal _test-output-stream " 0f 2f/compare *(ebp+0xfffffffc) 0x00000001/x32" "F - test-convert-floating-point-operation/34") + (check-next-stream-line-equal _test-output-stream " f3 0f 10/-> *esp 5/x32" "F - test-convert-floating-point-operation/35") + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 4/imm32" "F - test-convert-floating-point-operation/36") + (check-next-stream-line-equal _test-output-stream " f3 0f 10/-> *esp 1/x32" "F - test-convert-floating-point-operation/37") + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 4/imm32" "F - test-convert-floating-point-operation/38") + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-floating-point-operation/39") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-floating-point-operation/40") + (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:" "F - test-convert-floating-point-operation/41") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-floating-point-operation/42") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-floating-point-operation/43") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-floating-point-operation/44") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-floating-point-operation/45") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-floating-point-dereferenced: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn f {\n") + (write _test-input-stream " var m: float\n") + (write _test-input-stream " var x/xmm1: float <- copy m\n") + (write _test-input-stream " var y/eax: (addr float) <- copy 0\n") + (write _test-input-stream " x <- multiply *y\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "f:" "F - test-convert-floating-point-dereferenced/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-floating-point-dereferenced/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-floating-point-dereferenced/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-floating-point-dereferenced/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-floating-point-dereferenced/4") + (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:" "F - test-convert-floating-point-dereferenced/5") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-floating-point-dereferenced/6") + (check-next-stream-line-equal _test-output-stream " 81 5/subop/subtract %esp 4/imm32" "F - test-convert-floating-point-dereferenced/7") + (check-next-stream-line-equal _test-output-stream " f3 0f 11/<- *esp 1/x32" "F - test-convert-floating-point-dereferenced/8") + (check-next-stream-line-equal _test-output-stream " f3 0f 10/copy *(ebp+0xfffffffc) 0x00000001/x32" "F - test-convert-floating-point-dereferenced/9") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-floating-point-dereferenced/10") + (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-floating-point-dereferenced/11") + (check-next-stream-line-equal _test-output-stream " f3 0f 59/multiply *eax 0x00000001/x32" "F - test-convert-floating-point-dereferenced/12") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-floating-point-dereferenced/13") + (check-next-stream-line-equal _test-output-stream " f3 0f 10/-> *esp 1/x32" "F - test-convert-floating-point-dereferenced/14") + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 4/imm32" "F - test-convert-floating-point-dereferenced/15") + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-floating-point-dereferenced/16") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-floating-point-dereferenced/17") + (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:" "F - test-convert-floating-point-dereferenced/18") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-floating-point-dereferenced/19") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-floating-point-dereferenced/20") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-floating-point-dereferenced/21") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-floating-point-dereferenced/22") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-length-of-array: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo a: (addr array int) {\n") + (write _test-input-stream " var b/eax: (addr array int) <- copy a\n") + (write _test-input-stream " var c/eax: int <- length b\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-length-of-array/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-length-of-array/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-length-of-array/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-length-of-array/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-length-of-array/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-length-of-array/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-length-of-array/6") + (check-next-stream-line-equal _test-output-stream " 8b/-> *(ebp+0x00000008) 0x00000000/r32" "F - test-convert-length-of-array/7") + (check-next-stream-line-equal _test-output-stream " 8b/-> *eax 0x00000000/r32" "F - test-convert-length-of-array/8") + (check-next-stream-line-equal _test-output-stream " c1/shift 5/subop/>> %eax 0x00000002/imm8" "F - test-convert-length-of-array/9") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-length-of-array/10") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-length-of-array/11") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-length-of-array/12") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-length-of-array/13") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-length-of-array/14") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-length-of-array/15") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-length-of-array/16") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# special-case for size(byte) when computing array length +test-convert-length-of-array-of-bytes: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo a: (addr array byte) {\n") + (write _test-input-stream " var b/eax: (addr array byte) <- copy a\n") + (write _test-input-stream " var c/eax: int <- length b\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-length-of-array-of-bytes/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-length-of-array-of-bytes/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-length-of-array-of-bytes/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-length-of-array-of-bytes/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-length-of-array-of-bytes/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-length-of-array-of-bytes/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-length-of-array-of-bytes/6") + (check-next-stream-line-equal _test-output-stream " 8b/-> *(ebp+0x00000008) 0x00000000/r32" "F - test-convert-length-of-array-of-bytes/7") + (check-next-stream-line-equal _test-output-stream " 8b/-> *eax 0x00000000/r32" "F - test-convert-length-of-array-of-bytes/8") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-length-of-array-of-bytes/9") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-length-of-array-of-bytes/10") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-length-of-array-of-bytes/11") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-length-of-array-of-bytes/12") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-length-of-array-of-bytes/13") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-length-of-array-of-bytes/14") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-length-of-array-of-bytes/15") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-length-of-array-on-stack: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (array int 3)\n") + (write _test-input-stream " var b/eax: int <- length a\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-length-of-array-on-stack/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-length-of-array-on-stack/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-length-of-array-on-stack/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-length-of-array-on-stack/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-length-of-array-on-stack/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-length-of-array-on-stack/5") + # define x + (check-next-stream-line-equal _test-output-stream " (push-n-zero-bytes 0x0000000c)" "F - test-convert-length-of-array-on-stack/6") + (check-next-stream-line-equal _test-output-stream " 68/push 0x0000000c/imm32" "F - test-convert-length-of-array-on-stack/7") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-length-of-array-on-stack/8") + (check-next-stream-line-equal _test-output-stream " 8b/-> *(ebp+0xfffffff0) 0x00000000/r32" "F - test-convert-length-of-array-on-stack/9") + (check-next-stream-line-equal _test-output-stream " c1/shift 5/subop/>> %eax 0x00000002/imm8" "F - test-convert-length-of-array-on-stack/10") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-length-of-array-on-stack/11") + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000010/imm32" "F - test-convert-length-of-array-on-stack/12") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-length-of-array-on-stack/13") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-length-of-array-on-stack/14") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-length-of-array-on-stack/15") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-length-of-array-on-stack/16") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-length-of-array-on-stack/17") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-length-of-array-on-stack/18") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-reg-var-def-with-read-of-same-register: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) # bytes of args in call to convert-mu + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: int <- copy 3\n") + (write _test-input-stream " var y/eax: int <- add x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp could be clobbered at this point (though they shouldn't be) + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + (check-stream-equal _test-error-stream "" "F - test-reg-var-def-with-read-of-same-register: error stream should be empty") + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-reg-var-def-with-read-of-same-register/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-reg-var-def-with-read-of-same-register/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-reg-var-def-with-read-of-same-register/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-reg-var-def-with-read-of-same-register/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-reg-var-def-with-read-of-same-register/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-reg-var-def-with-read-of-same-register/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-reg-var-def-with-read-of-same-register/6") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-reg-var-def-with-read-of-same-register/9") + (check-next-stream-line-equal _test-output-stream " }" "F - test-reg-var-def-with-read-of-same-register/10") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-reg-var-def-with-read-of-same-register/11") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-reg-var-def-with-read-of-same-register/12") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-reg-var-def-with-read-of-same-register/13") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-reg-var-def-with-read-of-same-register/14") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-reg-var-def-with-read-of-same-register/15") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-index-into-array: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var arr/eax: (addr array int) <- copy 0\n") + (write _test-input-stream " var idx/ecx: int <- copy 3\n") + (write _test-input-stream " var x/eax: (addr int) <- index arr, idx\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-index-into-array/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-index-into-array/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-index-into-array/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-index-into-array/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-index-into-array/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-index-into-array/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array/6") + (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-index-into-array/7") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-index-into-array/8") + (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-convert-index-into-array/9") + (check-next-stream-line-equal _test-output-stream " (__check-mu-array-bounds %ecx 0x00000004 *eax \"foo\" \"arr\")" "F - test-convert-index-into-array/10") + (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx<<0x00000002 + 4) 0x00000000/r32" "F - test-convert-index-into-array/11") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array/12") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array/13") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array/14") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array/15") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array/16") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array/17") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array/18") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array/19") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-index-into-array-of-bytes: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var arr/eax: (addr array byte) <- copy 0\n") + (write _test-input-stream " var idx/ecx: int <- copy 3\n") + (write _test-input-stream " var x/eax: (addr byte) <- index arr, idx\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-index-into-array-of-bytes/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-index-into-array-of-bytes/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-index-into-array-of-bytes/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-index-into-array-of-bytes/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-index-into-array-of-bytes/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-index-into-array-of-bytes/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array-of-bytes/6") + (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-index-into-array-of-bytes/7") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-index-into-array-of-bytes/8") + (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-convert-index-into-array-of-bytes/9") + (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") + (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx<<0x00000000 + 4) 0x00000000/r32" "F - test-convert-index-into-array-of-bytes/11") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-of-bytes/12") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-of-bytes/13") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-of-bytes/14") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-of-bytes/15") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-of-bytes/16") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-of-bytes/17") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-of-bytes/18") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-of-bytes/19") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-index-into-array-with-literal: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var arr/eax: (addr array int) <- copy 0\n") + (write _test-input-stream " var x/eax: (addr int) <- index arr, 2\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-index-into-array-with-literal/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-index-into-array-with-literal/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-index-into-array-with-literal/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-index-into-array-with-literal/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-index-into-array-with-literal/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-index-into-array-with-literal/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array-with-literal/6") + (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-index-into-array-with-literal/7") + (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") + # 2 * 4 bytes/elem + 4 bytes for size = offset 12 + (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + 0x0000000c) 0x00000000/r32" "F - test-convert-index-into-array-with-literal/9") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-with-literal/10") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-with-literal/11") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-with-literal/12") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-with-literal/13") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-with-literal/14") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-with-literal/15") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-with-literal/16") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-index-into-array-of-bytes-with-literal: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var arr/eax: (addr array byte) <- copy 0\n") + (write _test-input-stream " var x/eax: (addr byte) <- index arr, 2\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-index-into-array-of-bytes-with-literal/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-index-into-array-of-bytes-with-literal/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-index-into-array-of-bytes-with-literal/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-index-into-array-of-bytes-with-literal/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-index-into-array-of-bytes-with-literal/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-index-into-array-of-bytes-with-literal/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array-of-bytes-with-literal/6") + (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") + (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") + # 2 * 1 byte/elem + 4 bytes for size = offset 6 + (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + 0x00000006) 0x00000000/r32" "F - test-convert-index-into-array-of-bytes-with-literal/8") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-of-bytes-with-literal/9") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-of-bytes-with-literal/10") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-of-bytes-with-literal/11") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-of-bytes-with-literal/12") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-of-bytes-with-literal/13") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-of-bytes-with-literal/14") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-of-bytes-with-literal/15") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-index-into-array-on-stack: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var arr: (array int 3)\n") + (write _test-input-stream " var idx/eax: int <- copy 2\n") + (write _test-input-stream " var x/eax: (addr int) <- index arr, idx\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-index-into-array-on-stack/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-index-into-array-on-stack/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-index-into-array-on-stack/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-index-into-array-on-stack/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-index-into-array-on-stack/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-index-into-array-on-stack/5") + # var arr + (check-next-stream-line-equal _test-output-stream " (push-n-zero-bytes 0x0000000c)" "F - test-convert-index-into-array-on-stack/6") + (check-next-stream-line-equal _test-output-stream " 68/push 0x0000000c/imm32" "F - test-convert-index-into-array-on-stack/7") + # var idx + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array-on-stack/8") + (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 2/imm32" "F - test-convert-index-into-array-on-stack/9") + (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") + # var x is at (ebp-0x10) + idx<<2 + 4 = ebp + idx<<2 - 0xc + (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") + # reclaim idx + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-on-stack/12") + # reclaim arr + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000010/imm32" "F - test-convert-index-into-array-on-stack/13") + # + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-on-stack/14") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-on-stack/15") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-on-stack/16") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-on-stack/17") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-on-stack/18") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-on-stack/19") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-index-into-array-on-stack-with-literal: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var arr: (array int 3)\n") + (write _test-input-stream " var x/eax: (addr int) <- index arr, 2\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-index-into-array-on-stack-with-literal/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-index-into-array-on-stack-with-literal/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-index-into-array-on-stack-with-literal/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-index-into-array-on-stack-with-literal/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-index-into-array-on-stack-with-literal/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-index-into-array-on-stack-with-literal/5") + # var arr + (check-next-stream-line-equal _test-output-stream " (push-n-zero-bytes 0x0000000c)" "F - test-convert-index-into-array-on-stack-with-literal/6") + (check-next-stream-line-equal _test-output-stream " 68/push 0x0000000c/imm32" "F - test-convert-index-into-array-on-stack-with-literal/7") + # var x + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array-on-stack-with-literal/8") + (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") + # x is at (ebp-0x10) + 4 + 2*4 = ebp-4 + (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") + # reclaim x + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-on-stack-with-literal/11") + # reclaim arr + (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") + # + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-on-stack-with-literal/13") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-on-stack-with-literal/14") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-on-stack-with-literal/15") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-on-stack-with-literal/16") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-on-stack-with-literal/17") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-on-stack-with-literal/18") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-index-into-array-of-bytes-on-stack-with-literal: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var arr: (array byte 3)\n") + (write _test-input-stream " var x/eax: (addr byte) <- index arr, 2\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/2") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/5") + # var arr + (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") + (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") + # var x + (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") + (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") + # x is at (ebp-7) + 4 + 2 = ebp-1 + (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") + # reclaim x + (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") + # reclaim arr + (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") + # + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/13") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/14") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/15") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/18") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-index-into-array-using-offset: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var arr/eax: (addr array int) <- copy 0\n") + (write _test-input-stream " var idx/ecx: int <- copy 3\n") + (write _test-input-stream " var off/ecx: (offset int) <- compute-offset arr, idx\n") + (write _test-input-stream " var x/eax: (addr int) <- index arr, off\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-index-into-array-using-offset/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-index-into-array-using-offset/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-index-into-array-using-offset/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-index-into-array-using-offset/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-index-into-array-using-offset/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-index-into-array-using-offset/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array-using-offset/6") + (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-index-into-array-using-offset/7") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-index-into-array-using-offset/8") + (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-convert-index-into-array-using-offset/9") + (check-next-stream-line-equal _test-output-stream " 69/multiply %ecx 0x00000004/imm32 0x00000001/r32" "F - test-convert-index-into-array-using-offset/10") + (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") + (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx + 4) 0x00000000/r32" "F - test-convert-index-into-array-using-offset/12") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-using-offset/13") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-using-offset/14") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-using-offset/15") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-using-offset/16") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-using-offset/17") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-using-offset/18") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-using-offset/19") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-using-offset/20") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-index-into-array-of-bytes-using-offset: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var arr/eax: (addr array byte) <- copy 0\n") + (write _test-input-stream " var idx/ecx: int <- copy 3\n") + (write _test-input-stream " var off/ecx: (offset byte) <- compute-offset arr, idx\n") + (write _test-input-stream " var x/eax: (addr byte) <- index arr, off\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-index-into-array-of-bytes-using-offset/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-index-into-array-of-bytes-using-offset/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-index-into-array-of-bytes-using-offset/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-index-into-array-of-bytes-using-offset/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-index-into-array-of-bytes-using-offset/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-index-into-array-of-bytes-using-offset/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array-of-bytes-using-offset/6") + (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") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-index-into-array-of-bytes-using-offset/8") + (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") + (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") + (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") + (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/12") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-of-bytes-using-offset/13") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-of-bytes-using-offset/14") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-of-bytes-using-offset/15") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-of-bytes-using-offset/16") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-of-bytes-using-offset/17") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-of-bytes-using-offset/18") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-of-bytes-using-offset/19") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-of-bytes-using-offset/20") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-index-into-array-using-offset-on-stack: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var arr/eax: (addr array int) <- copy 0\n") + (write _test-input-stream " var idx: int\n") + (write _test-input-stream " var off/ecx: (offset int) <- compute-offset arr, idx\n") + (write _test-input-stream " var x/eax: (addr int) <- index arr, off\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-index-into-array-using-offset-on-stack/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-index-into-array-using-offset-on-stack/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-index-into-array-using-offset-on-stack/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-index-into-array-using-offset-on-stack/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-index-into-array-using-offset-on-stack/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-index-into-array-using-offset-on-stack/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array-using-offset-on-stack/6") + (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") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-index-into-array-using-offset-on-stack/8") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-index-into-array-using-offset-on-stack/9") + (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") + (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") + (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/12") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-using-offset-on-stack/13") + (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/14") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-using-offset-on-stack/15") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-using-offset-on-stack/16") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-using-offset-on-stack/17") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-using-offset-on-stack/18") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-using-offset-on-stack/19") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-using-offset-on-stack/20") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-using-offset-on-stack/21") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-index-into-array-of-bytes-using-offset-on-stack: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var arr/eax: (addr array byte) <- copy 0\n") + (write _test-input-stream " var idx: int\n") + (write _test-input-stream " var off/ecx: (offset byte) <- compute-offset arr, idx\n") + (write _test-input-stream " var x/eax: (addr byte) <- index arr, off\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/2") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/5") + (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") + (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") + (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") + (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") + (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") + (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") + (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/12") + (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/13") + (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/14") + (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/15") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/16") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/17") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/18") + (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/19") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/20") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/21") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-and-type-definition: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo a: (addr t) {\n") + (write _test-input-stream " var _a/eax: (addr t) <- copy a\n") + (write _test-input-stream " var b/ecx: (addr int) <- get _a, x\n") + (write _test-input-stream " var c/ecx: (addr int) <- get _a, y\n") + (write _test-input-stream "}\n") + (write _test-input-stream "type t {\n") + (write _test-input-stream " x: int\n") + (write _test-input-stream " y: int\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-and-type-definition/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-and-type-definition/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-and-type-definition/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-and-type-definition/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-and-type-definition/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-and-type-definition/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-function-and-type-definition/6") + (check-next-stream-line-equal _test-output-stream " 8b/-> *(ebp+0x00000008) 0x00000000/r32" "F - test-convert-function-and-type-definition/7") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-function-and-type-definition/8") + (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + 0x00000000) 0x00000001/r32" "F - test-convert-function-and-type-definition/9") + (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + 0x00000004) 0x00000001/r32" "F - test-convert-function-and-type-definition/11") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-function-and-type-definition/13") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-function-and-type-definition/14") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-and-type-definition/15") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-and-type-definition/16") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-and-type-definition/17") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-and-type-definition/18") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-and-type-definition/19") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-and-type-definition/20") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-type-definition-with-array: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "type t {\n") + (write _test-input-stream " a: (array int 3)\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-type-definition-with-array: output should be empty") + (check-next-stream-line-equal _test-error-stream "type t: 'array' elements not allowed for now" "F - test-type-definition-with-array: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-type-definition-with-array: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-type-definition-with-addr: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "type t {\n") + (write _test-input-stream " a: (addr int)\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-type-definition-with-addr: output should be empty") + (check-next-stream-line-equal _test-error-stream "type t: 'addr' elements not allowed" "F - test-type-definition-with-addr: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-type-definition-with-addr: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-function-with-local-var-with-user-defined-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: t\n") + (write _test-input-stream "}\n") + (write _test-input-stream "type t {\n") + (write _test-input-stream " x: int\n") + (write _test-input-stream " y: int\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-var-with-user-defined-type/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-var-with-user-defined-type/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-var-with-user-defined-type/2") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-with-user-defined-type/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-var-with-user-defined-type/5") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-local-var-with-user-defined-type/6") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-local-var-with-user-defined-type/7") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-with-user-defined-type/9") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-var-with-user-defined-type/10") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-var-with-user-defined-type/11") + (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") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-local-var-with-user-defined-type/13") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-var-with-user-defined-type/14") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: t\n") + (write _test-input-stream "}\n") + (write _test-input-stream "type t {\n") + (write _test-input-stream " x: s\n") + (write _test-input-stream "}\n") + (write _test-input-stream "type s {\n") + (write _test-input-stream " z: int\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (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") + (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") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/4") + (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") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/9") + (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") + (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") + (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") + (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") + (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") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-call-with-arg-of-user-defined-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn f {\n") + (write _test-input-stream " var a: t\n") + (write _test-input-stream " foo a\n") + (write _test-input-stream "}\n") + (write _test-input-stream "fn foo x: t {\n") + (write _test-input-stream "}\n") + (write _test-input-stream "type t {\n") + (write _test-input-stream " x: int\n") + (write _test-input-stream " y: int\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "f:" "F - test-convert-function-call-with-arg-of-user-defined-type/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-arg-of-user-defined-type/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/2") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-call-with-arg-of-user-defined-type/4") + (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:" "F - test-convert-function-call-with-arg-of-user-defined-type/5") + # var a: t + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-call-with-arg-of-user-defined-type/6") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-call-with-arg-of-user-defined-type/7") + # foo a + (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") + # + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-call-with-arg-of-user-defined-type/10") + (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:" "F - test-convert-function-call-with-arg-of-user-defined-type/11") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-arg-of-user-defined-type/12") + (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") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/14") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-arg-of-user-defined-type/15") + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-call-with-arg-of-user-defined-type/16") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-arg-of-user-defined-type/17") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/18") + (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") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-arg-of-user-defined-type/20") + (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") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/22") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-arg-of-user-defined-type/23") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-call-with-arg-of-user-defined-type-register-indirect: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn f {\n") + (write _test-input-stream " var a/eax: (addr t) <- copy 0\n") + (write _test-input-stream " foo *a\n") + (write _test-input-stream "}\n") + (write _test-input-stream "fn foo x: t {\n") + (write _test-input-stream "}\n") + (write _test-input-stream "type t {\n") + (write _test-input-stream " x: int\n") + (write _test-input-stream " y: int\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "f:" "F - test-convert-function-call-with-arg-of-user-defined-type/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-arg-of-user-defined-type/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/2") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-call-with-arg-of-user-defined-type/4") + (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:" "F - test-convert-function-call-with-arg-of-user-defined-type/5") + # var a + (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") + (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") + # foo a + (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") + # + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-call-with-arg-of-user-defined-type/10") + (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:" "F - test-convert-function-call-with-arg-of-user-defined-type/11") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-arg-of-user-defined-type/12") + (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") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/14") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-arg-of-user-defined-type/15") + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-call-with-arg-of-user-defined-type/16") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-arg-of-user-defined-type/17") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/18") + (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") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-arg-of-user-defined-type/20") + (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") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type/22") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-arg-of-user-defined-type/23") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# we don't have special support for call-by-reference; just explicitly create +# a new variable with the address of the arg +test-convert-function-call-with-arg-of-user-defined-type-by-reference: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn f {\n") + (write _test-input-stream " var a: t\n") + (write _test-input-stream " var b/eax: (addr t) <- address a\n") + (write _test-input-stream " foo b\n") + (write _test-input-stream "}\n") + (write _test-input-stream "fn foo x: (addr t) {\n") + (write _test-input-stream " var x/ecx: (addr t) <- copy x\n") + (write _test-input-stream "}\n") + (write _test-input-stream "type t {\n") + (write _test-input-stream " x: int\n") + (write _test-input-stream " y: int\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "f:" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/1") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/4") + (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") + # var a: t + (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") + (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") + # var b/eax: (addr t) + (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") + (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") + # foo a + (check-next-stream-line-equal _test-output-stream " (foo %eax)" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/10") + # + (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") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/13") + (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") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/15") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/18") + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/19") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/20") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/23") + (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") + (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") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/28") + (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") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/30") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/33") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-get-on-local-variable: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: t\n") + (write _test-input-stream " var c/ecx: (addr int) <- get a, y\n") + (write _test-input-stream "}\n") + (write _test-input-stream "type t {\n") + (write _test-input-stream " x: int\n") + (write _test-input-stream " y: int\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-get-on-local-variable/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-get-on-local-variable/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-get-on-local-variable/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-get-on-local-variable/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-get-on-local-variable/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-get-on-local-variable/5") + # var a + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-get-on-local-variable/6") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-get-on-local-variable/7") + # var c + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-get-on-local-variable/8") + # get + (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(ebp+0xfffffffc) 0x00000001/r32" "F - test-convert-get-on-local-variable/9") + # reclaim c + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-get-on-local-variable/10") + # reclaim a + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000008/imm32" "F - test-convert-get-on-local-variable/11") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-get-on-local-variable/12") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-get-on-local-variable/13") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-get-on-local-variable/14") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-get-on-local-variable/15") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-get-on-local-variable/16") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-get-on-local-variable/17") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-get-on-function-argument: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo a: t {\n") + (write _test-input-stream " var c/ecx: (addr int) <- get a, y\n") + (write _test-input-stream "}\n") + (write _test-input-stream "type t {\n") + (write _test-input-stream " x: int\n") + (write _test-input-stream " y: int\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-get-on-function-argument/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-get-on-function-argument/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-get-on-function-argument/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-get-on-function-argument/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-get-on-function-argument/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-get-on-function-argument/5") + # var c + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-get-on-function-argument/6") + # get + (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(ebp+0x0000000c) 0x00000001/r32" "F - test-convert-get-on-function-argument/7") + # reclaim c + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument/8") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-get-on-function-argument/9") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-get-on-function-argument/10") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-get-on-function-argument/11") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-get-on-function-argument/12") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-get-on-function-argument/13") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-get-on-function-argument/14") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-get-on-function-argument-with-known-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "type t {\n") + (write _test-input-stream " x: int\n") + (write _test-input-stream " y: int\n") + (write _test-input-stream "}\n") + (write _test-input-stream "fn foo a: t {\n") + (write _test-input-stream " var c/ecx: (addr int) <- get a, y\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-get-on-function-argument-with-known-type/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-get-on-function-argument-with-known-type/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-get-on-function-argument-with-known-type/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-get-on-function-argument-with-known-type/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-get-on-function-argument-with-known-type/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-get-on-function-argument-with-known-type/5") + # var c + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-get-on-function-argument-with-known-type/6") + # get + (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") + # reclaim c + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument-with-known-type/8") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-get-on-function-argument-with-known-type/9") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-get-on-function-argument-with-known-type/10") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-get-on-function-argument-with-known-type/11") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-get-on-function-argument-with-known-type/12") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-get-on-function-argument-with-known-type/13") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-get-on-function-argument-with-known-type/14") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-add-with-too-many-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: int\n") + (write _test-input-stream " var b/ecx: int <- add a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-add-with-too-many-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-add-with-too-many-inouts-2: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: int\n") + (write _test-input-stream " add-to a, 0, 1\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-add-with-too-many-inouts-2: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-inouts-2: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-add-with-too-many-outputs: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a/eax: int <- copy 0\n") + (write _test-input-stream " var b/ebx: int <- copy 0\n") + (write _test-input-stream " var c/ecx: int <- copy 0\n") + (write _test-input-stream " c, b <- add a\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-add-with-too-many-outputs: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-outputs: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-add-with-non-number: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: int\n") + (write _test-input-stream " var b/ecx: (addr int) <- add a\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-add-with-non-number: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-add-with-non-number: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-add-with-addr-dereferenced: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a/eax: (addr int) <- copy 0\n") + (write _test-input-stream " add-to *a, 1\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) + # no error + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-copy-with-no-inout: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: boolean <- copy\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-with-no-inout: output should be empty") + (check-next-stream-line-equal _test-error-stream "fn foo: stmt 'copy' expects an inout" "F - test-copy-with-no-inout: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-with-no-inout: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-with-multiple-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: boolean <- copy 0, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-with-multiple-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-with-multiple-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-with-no-output: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " copy 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-with-no-output: output should be empty") + (check-next-stream-line-equal _test-error-stream "fn foo: stmt 'copy' expects an output" "F - test-copy-with-no-output: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-with-no-output: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-with-multiple-outputs: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: boolean <- copy 0\n") + (write _test-input-stream " var y/ecx: boolean <- copy 0\n") + (write _test-input-stream " x, y <- copy 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-with-multiple-outputs: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-with-multiple-outputs: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-invalid-value-to-address: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: int <- copy 0\n") + (write _test-input-stream " var y/ecx: (addr int) <- copy x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-invalid-value-to-address: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-invalid-value-to-address: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-null-value-to-address: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var y/ecx: (addr int) <- copy 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) + # no errors + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-copy-invalid-value-to-offset: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: int <- copy 0\n") + (write _test-input-stream " var y/ecx: (offset int) <- copy x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-invalid-value-to-address: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-invalid-value-to-offset: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-null-value-to-offset: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var y/ecx: (offset int) <- copy 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # no errors + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-copy-non-literal-to-byte: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/ecx: int <- copy 3\n") + (write _test-input-stream " var y/ecx: byte <- copy x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-non-literal-to-byte: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-non-literal-to-byte: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-deref-address: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: (addr addr int) <- copy 0\n") + (write _test-input-stream " var y/ecx: (addr int) <- copy *x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) + # no errors + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-to-non-register: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: int\n") + (write _test-input-stream " x <- copy 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-to-non-register: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-to-non-register: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-from-non-scalar-inout: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: (handle int)\n") + (write _test-input-stream " var y/eax: int <- copy x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-from-non-scalar-inout: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-from-non-scalar-inout: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-to-with-no-inout: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " copy-to\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-to-with-no-inout: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-to-with-no-inout: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-to-with-no-source: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: boolean\n") + (write _test-input-stream " copy-to x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-to-with-no-source: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-to-with-no-source: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-to-with-no-register: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: boolean\n") + (write _test-input-stream " copy-to x, x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-to-with-no-register: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-to-with-no-register: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-to-with-too-many-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: boolean\n") + (write _test-input-stream " copy-to x, 0, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-to-with-too-many-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-to-with-too-many-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-to-with-output: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: boolean <- copy 0\n") + (write _test-input-stream " var y/ecx: boolean <- copy 0\n") + (write _test-input-stream " x <- copy-to y, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-to-with-output: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-to-with-output: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-to-invalid-value-to-address: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: int <- copy 0\n") + (write _test-input-stream " var y: (addr int)\n") + (write _test-input-stream " copy-to y, x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-to-invalid-value-to-address: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-to-invalid-value-to-address: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-to-null-value-to-address: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var y: (addr int)\n") + (write _test-input-stream " copy-to y, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) + # no errors + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-copy-to-invalid-value-to-offset: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: int <- copy 0\n") + (write _test-input-stream " var y: (offset int)\n") + (write _test-input-stream " copy-to y, x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-to-invalid-value-to-offset: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-to-invalid-value-to-offset: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-to-null-value-to-offset: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var y: (offset int)\n") + (write _test-input-stream " copy-to y, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) + # no errors + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-copy-to-non-literal-to-byte: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/ecx: byte <- copy 3\n") + (write _test-input-stream " var y/eax: (addr byte) <- copy 0\n") + (write _test-input-stream " copy-to *y, x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-to-non-literal-to-byte: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-to-non-literal-to-byte: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-to-deref-address: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: (addr int) <- copy 0\n") + (write _test-input-stream " var y/ecx: (addr addr int) <- copy 0\n") + (write _test-input-stream " copy-to *y, x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) + # no errors + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-to-from-non-scalar-inout: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: (handle int)\n") + (write _test-input-stream " var y: int\n") + (write _test-input-stream " copy-to y, x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-to-from-non-scalar-inout: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-to-from-non-scalar-inout: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-byte-with-no-inout: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: byte <- copy-byte\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-byte-with-no-inout: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-byte-with-no-inout: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-byte-with-multiple-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: byte <- copy-byte 0, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-byte-with-multiple-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-byte-with-multiple-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-byte-with-no-output: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " copy-byte 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-byte-with-no-output: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-byte-with-no-output: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-byte-with-multiple-outputs: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: byte <- copy 0\n") + (write _test-input-stream " var y/ecx: byte <- copy 0\n") + (write _test-input-stream " x, y <- copy-byte 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-byte-with-multiple-outputs: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-byte-with-multiple-outputs: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-byte-deref-address: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: (addr byte) <- copy 0\n") + (write _test-input-stream " var y/ecx: byte <- copy-byte *x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # not bothering checking output + (check-next-stream-line-equal _test-error-stream "" "F - test-copy-byte-deref-address: error message") + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-byte-with-invalid-output-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: (addr byte) <- copy 0\n") + (write _test-input-stream " var y/eax: int <- copy-byte *x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-byte-with-invalid-output-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-byte-with-invalid-output-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-byte-from-non-scalar-inout: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: (handle int)\n") + (write _test-input-stream " var y/eax: byte <- copy-byte x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-byte-from-non-scalar-inout: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-byte-from-non-scalar-inout: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-byte-to-with-no-inout: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " copy-byte-to\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-byte-to-with-no-inout: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-byte-to-with-no-inout: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-byte-to-with-no-source: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: (addr byte) <- copy 0\n") + (write _test-input-stream " copy-byte-to *x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-byte-to-with-no-source: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-byte-to-with-no-source: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-byte-to-with-too-many-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: (addr byte) <- copy 0\n") + (write _test-input-stream " copy-byte-to *x, 0, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-byte-to-with-too-many-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-byte-to-with-too-many-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-byte-to-with-output: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: byte <- copy 0\n") + (write _test-input-stream " var y/ecx: (addr byte) <- copy 0\n") + (write _test-input-stream " x <- copy-byte-to *y, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-byte-to-with-output: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-byte-to-with-output: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-byte-to-with-invalid-output-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: byte <- copy 0\n") + (write _test-input-stream " var y: int\n") + (write _test-input-stream " copy-byte-to y, x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-byte-to-with-invalid-output-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-byte-to-with-invalid-output-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-byte-to-with-literal-inout: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: (addr byte) <- copy 0\n") + (write _test-input-stream " copy-byte-to *x, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-byte-to-with-literal-inout: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-byte-to-with-literal-inout: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-byte-to-deref-address: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: byte <- copy 0\n") + (write _test-input-stream " var y/ecx: (addr byte) <- copy 0\n") + (write _test-input-stream " copy-byte-to *y, x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) + # no errors + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-byte-to-from-non-scalar-inout: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: (handle int)\n") + (write _test-input-stream " var y/eax: (addr byte) <- copy 0\n") + (write _test-input-stream " copy-byte-to *y, x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-byte-to-from-non-scalar-inout: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-byte-to-from-non-scalar-inout: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-compare-with-no-inout: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: boolean\n") + (write _test-input-stream " compare\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-compare-with-no-inout: output should be empty") + (check-next-stream-line-equal _test-error-stream "fn foo: stmt 'compare' must have two inouts" "F - test-compare-with-no-inout: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-compare-with-no-inout: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-compare-with-just-one-inout: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: boolean\n") + (write _test-input-stream " compare x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-compare-with-just-one-inout: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-compare-with-just-one-inout: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-compare-with-too-many-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: boolean\n") + (write _test-input-stream " compare x, 0, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-compare-with-too-many-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-compare-with-too-many-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-compare-with-output: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: boolean <- copy 0\n") + (write _test-input-stream " var y/ecx: boolean <- copy 0\n") + (write _test-input-stream " x <- compare y, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-compare-with-output: output should be empty") + (check-next-stream-line-equal _test-error-stream "fn foo: stmt 'compare' must not have any outputs" "F - test-compare-with-output: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-compare-with-output: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-compare-invalid-value-to-address: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: int <- copy 0\n") + (write _test-input-stream " var y: (addr int)\n") + (write _test-input-stream " compare y, x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-compare-invalid-value-to-address: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-compare-invalid-value-to-address: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-compare-address: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: (addr int) <- copy 0\n") + (write _test-input-stream " var y/ecx: (addr int) <- copy 0\n") + (write _test-input-stream " compare y, x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) + # no errors + # . epilogue + 5d/pop-to-ebp + c3/return + +test-compare-deref-address: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: (addr int) <- copy 0\n") + (write _test-input-stream " var y/ecx: (addr addr int) <- copy 0\n") + (write _test-input-stream " compare *y, x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) + # no errors + # . epilogue + 5d/pop-to-ebp + c3/return + +test-compare-two-vars-in-memory: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: boolean\n") + (write _test-input-stream " compare x, x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-compare-two-vars-in-memory: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-compare-two-vars-in-memory: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-compare-non-scalar: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: (handle int)\n") + (write _test-input-stream " var y: int\n") + (write _test-input-stream " compare y, x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-compare-non-scalar: output should be empty") +#? (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") + (check-next-stream-line-equal _test-error-stream "fn foo: stmt compare: both inouts are in memory" "F - test-compare-non-scalar: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-compare-non-scalar: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-compare-with-string-literal: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: (addr array byte) <- copy 0\n") + (write _test-input-stream " compare x, \"abc\"\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-compare-with-string-literal: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-compare-with-string-literal: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-address-with-no-inout: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: boolean <- address\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-address-with-no-inout: output should be empty") + (check-next-stream-line-equal _test-error-stream "fn foo: stmt 'address' expects an inout" "F - test-address-with-no-inout: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-address-with-no-inout: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-address-with-multiple-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: boolean <- address 0, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-address-with-multiple-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-address-with-multiple-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-address-with-no-output: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " address 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-address-with-no-output: output should be empty") + (check-next-stream-line-equal _test-error-stream "fn foo: stmt 'address' expects an output" "F - test-address-with-no-output: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-address-with-no-output: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-address-with-multiple-outputs: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: boolean <- copy 0\n") + (write _test-input-stream " var y/ecx: boolean <- copy 0\n") + (write _test-input-stream " x, y <- address 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-address-with-multiple-outputs: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-address-with-multiple-outputs: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +# silly but it works +test-address-of-deref: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: (addr int) <- copy 0\n") + (write _test-input-stream " var y/ecx: (addr int) <- address *x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) + # no errors + # . epilogue + 5d/pop-to-ebp + c3/return + +test-address-to-non-register: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: (addr int)\n") + (write _test-input-stream " x <- address 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-address-to-non-register: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-address-to-non-register: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-address-with-wrong-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: int\n") + (write _test-input-stream " var y/eax: (addr boolean) <- address x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-address-with-wrong-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-address-with-wrong-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-address-with-right-type-for-array: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: (array int 3)\n") + (write _test-input-stream " var y/eax: (addr array int) <- address x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) + # no errors + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-address-with-right-type-for-stream: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: (stream int 3)\n") + (write _test-input-stream " var y/eax: (addr stream int) <- address x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) + # no errors + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-get-with-wrong-field: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: t\n") + (write _test-input-stream " var c/ecx: (addr int) <- get a, y\n") + (write _test-input-stream "}\n") + (write _test-input-stream "type t {\n") + (write _test-input-stream " x: int\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-get-with-wrong-field: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-field: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-get-with-wrong-base-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: int\n") + (write _test-input-stream " var c/ecx: (addr int) <- get a, y\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-get-with-wrong-base-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-base-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-get-with-wrong-base-type-2: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (addr t)\n") + (write _test-input-stream " var c/ecx: (addr int) <- get a, y\n") + (write _test-input-stream "}\n") + (write _test-input-stream "type t {\n") + (write _test-input-stream " x: int\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-get-with-wrong-base-type-2: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-base-type-2: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-get-with-wrong-base-type-3: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (handle int)\n") + (write _test-input-stream " var c/ecx: (addr int) <- get a, y\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-get-with-wrong-base-type-3: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-base-type-3: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-get-with-wrong-offset-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: t\n") + (write _test-input-stream " var b: int\n") + (write _test-input-stream " var c/ecx: (addr int) <- get a, b\n") + (write _test-input-stream "}\n") + (write _test-input-stream "type t {\n") + (write _test-input-stream " x: int\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-get-with-wrong-offset-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-offset-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-get-with-wrong-output-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: t\n") + (write _test-input-stream " var c: (addr int)\n") + (write _test-input-stream " c <- get a, x\n") + (write _test-input-stream "}\n") + (write _test-input-stream "type t {\n") + (write _test-input-stream " x: int\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-get-with-wrong-output-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-get-with-wrong-output-type-2: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: t\n") + (write _test-input-stream " var c/ecx: int <- get a, x\n") + (write _test-input-stream "}\n") + (write _test-input-stream "type t {\n") + (write _test-input-stream " x: int\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-get-with-wrong-output-type-2: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-2: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-get-with-wrong-output-type-3: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: t\n") + (write _test-input-stream " var c/ecx: (array int) <- get a, x\n") + (write _test-input-stream "}\n") + (write _test-input-stream "type t {\n") + (write _test-input-stream " x: int\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-get-with-wrong-output-type-3: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-3: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-get-with-wrong-output-type-4: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: t\n") + (write _test-input-stream " var c/ecx: (addr boolean) <- get a, x\n") + (write _test-input-stream "}\n") + (write _test-input-stream "type t {\n") + (write _test-input-stream " x: int\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-get-with-wrong-output-type-4: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-4: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-get-with-wrong-output-type-5: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: t\n") + (write _test-input-stream " var c/ecx: (addr handle int) <- get a, x\n") + (write _test-input-stream "}\n") + (write _test-input-stream "type t {\n") + (write _test-input-stream " x: (handle int)\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) + # no errors + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-get-with-too-few-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: t\n") + (write _test-input-stream " var c/ecx: (addr int) <- get a\n") + (write _test-input-stream "}\n") + (write _test-input-stream "type t {\n") + (write _test-input-stream " x: int\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-get-with-too-few-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-get-with-too-few-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-get-with-too-many-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: t\n") + (write _test-input-stream " var c/ecx: (addr int) <- get a, x, 0\n") + (write _test-input-stream "}\n") + (write _test-input-stream "type t {\n") + (write _test-input-stream " x: int\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-get-with-too-many-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-get-with-too-many-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-get-with-no-output: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: t\n") + (write _test-input-stream " get a, x\n") + (write _test-input-stream "}\n") + (write _test-input-stream "type t {\n") + (write _test-input-stream " x: int\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-get-with-no-output: output should be empty") + (check-next-stream-line-equal _test-error-stream "fn foo: stmt get: must have an output" "F - test-get-with-no-output: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-get-with-no-output: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-get-with-too-many-outputs: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: t\n") + (write _test-input-stream " var b: int\n") + (write _test-input-stream " var c/eax: (addr int) <- copy 0\n") + (write _test-input-stream " c, b <- get a, x\n") + (write _test-input-stream "}\n") + (write _test-input-stream "type t {\n") + (write _test-input-stream " x: int\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-get-with-too-many-outputs: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-get-with-too-many-outputs: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-array-of-user-defined-types: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "type t {\n") # each t is 8 bytes, which is a power of 2 + (write _test-input-stream " x: int\n") + (write _test-input-stream " y: int\n") + (write _test-input-stream "}\n") + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var arr/eax: (addr array t) <- copy 0\n") + (write _test-input-stream " var idx/ecx: int <- copy 3\n") + (write _test-input-stream " var x/eax: (addr t) <- index arr, idx\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-array-of-user-defined-types/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-array-of-user-defined-types/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-array-of-user-defined-types/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-array-of-user-defined-types/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-array-of-user-defined-types/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-array-of-user-defined-types/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-array-of-user-defined-types/6") + (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-array-of-user-defined-types/7") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-array-of-user-defined-types/8") + (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-convert-array-of-user-defined-types/9") + (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") + (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx<<0x00000003 + 4) 0x00000000/r32" "F - test-convert-array-of-user-defined-types/11") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-array-of-user-defined-types/12") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-array-of-user-defined-types/13") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-array-of-user-defined-types/14") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-array-of-user-defined-types/15") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-array-of-user-defined-types/16") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-array-of-user-defined-types/17") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-array-of-user-defined-types/18") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-array-of-user-defined-types/19") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-length-of-array-of-user-defined-types-to-eax: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "type t {\n") # size = 12, which is not a power of 2 + (write _test-input-stream " x: int\n") + (write _test-input-stream " y: int\n") + (write _test-input-stream " z: int\n") + (write _test-input-stream "}\n") + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var arr/eax: (addr array t) <- copy 0\n") + (write _test-input-stream " var x/eax: int <- length arr\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-length-of-array-of-user-defined-types-to-eax/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-length-of-array-of-user-defined-types-to-eax/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-length-of-array-of-user-defined-types-to-eax/2") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-length-of-array-of-user-defined-types-to-eax/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-length-of-array-of-user-defined-types-to-eax/5") + # var arr + (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") + (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") + # length instruction + (check-next-stream-line-equal _test-output-stream " 51/push-ecx" "F - test-convert-length-of-array-of-user-defined-types-to-eax/8") + (check-next-stream-line-equal _test-output-stream " 52/push-edx" "F - test-convert-length-of-array-of-user-defined-types-to-eax/9") + (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") + (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") + (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") + (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") + (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") + (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") + # reclaim arr + (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") + # + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-length-of-array-of-user-defined-types-to-eax/17") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-length-of-array-of-user-defined-types-to-eax/18") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-length-of-array-of-user-defined-types-to-eax/19") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-length-of-array-of-user-defined-types-to-eax/22") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-length-of-array-of-user-defined-types-to-ecx: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "type t {\n") # size = 12, which is not a power of 2 + (write _test-input-stream " x: int\n") + (write _test-input-stream " y: int\n") + (write _test-input-stream " z: int\n") + (write _test-input-stream "}\n") + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var arr/eax: (addr array t) <- copy 0\n") + (write _test-input-stream " var x/ecx: int <- length arr\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-length-of-array-of-user-defined-types-to-ecx/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-length-of-array-of-user-defined-types-to-ecx/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-length-of-array-of-user-defined-types-to-ecx/2") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-length-of-array-of-user-defined-types-to-ecx/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-length-of-array-of-user-defined-types-to-ecx/5") + # var a + (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") + (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") + # var x + (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") + # length instruction + (check-next-stream-line-equal _test-output-stream " 50/push-eax" "F - test-convert-length-of-array-of-user-defined-types-to-ecx/9") + (check-next-stream-line-equal _test-output-stream " 52/push-edx" "F - test-convert-length-of-array-of-user-defined-types-to-ecx/10") + (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") + (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") + (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") + (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") + (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") + (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") + (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") + # reclaim x + (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") + # reclaim a + (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") + # + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-length-of-array-of-user-defined-types-to-ecx/20") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-length-of-array-of-user-defined-types-to-ecx/21") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-length-of-array-of-user-defined-types-to-ecx/22") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-length-of-array-of-user-defined-types-to-ecx/25") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-length-of-array-of-user-defined-types-to-edx: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "type t {\n") # size = 12, which is not a power of 2 + (write _test-input-stream " x: int\n") + (write _test-input-stream " y: int\n") + (write _test-input-stream " z: int\n") + (write _test-input-stream "}\n") + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var arr/eax: (addr array t) <- copy 0\n") + (write _test-input-stream " var x/edx: int <- length arr\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-length-of-array-of-user-defined-types-to-edx/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-length-of-array-of-user-defined-types-to-edx/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-length-of-array-of-user-defined-types-to-edx/2") + (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") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-length-of-array-of-user-defined-types-to-edx/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-length-of-array-of-user-defined-types-to-edx/5") + # var a + (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") + (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") + # var x + (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") + # length instruction + (check-next-stream-line-equal _test-output-stream " 50/push-eax" "F - test-convert-length-of-array-of-user-defined-types-to-edx/9") + (check-next-stream-line-equal _test-output-stream " 51/push-ecx" "F - test-convert-length-of-array-of-user-defined-types-to-edx/10") + (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") + (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") + (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") + (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") + (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") + (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") + (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") + # reclaim x + (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") + # reclaim a + (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") + # + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-length-of-array-of-user-defined-types-to-edx/20") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-length-of-array-of-user-defined-types-to-edx/21") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-length-of-array-of-user-defined-types-to-edx/22") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-length-of-array-of-user-defined-types-to-edx/25") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-length-of-array-of-user-defined-types: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "type t {\n") # each t is 8 bytes, which is a power of 2 + (write _test-input-stream " x: int\n") + (write _test-input-stream " y: int\n") + (write _test-input-stream " z: int\n") + (write _test-input-stream "}\n") + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var arr/eax: (addr array t) <- copy 0\n") + (write _test-input-stream " var x/ebx: int <- length arr\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-length-of-array-of-user-defined-types/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-length-of-array-of-user-defined-types/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-length-of-array-of-user-defined-types/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-length-of-array-of-user-defined-types/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-length-of-array-of-user-defined-types/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-length-of-array-of-user-defined-types/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-length-of-array-of-user-defined-types/6") + (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") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ebx" "F - test-convert-length-of-array-of-user-defined-types/8") + (check-next-stream-line-equal _test-output-stream " 50/push-eax" "F - test-convert-length-of-array-of-user-defined-types/9") + (check-next-stream-line-equal _test-output-stream " 51/push-ecx" "F - test-convert-length-of-array-of-user-defined-types/10") + (check-next-stream-line-equal _test-output-stream " 52/push-edx" "F - test-convert-length-of-array-of-user-defined-types/11") + (check-next-stream-line-equal _test-output-stream " 8b/-> *eax 0x00000000/r32" "F - test-convert-length-of-array-of-user-defined-types/12") + (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") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebx 0/r32/eax" "F - test-convert-length-of-array-of-user-defined-types/16") + (check-next-stream-line-equal _test-output-stream " 5a/pop-to-edx" "F - test-convert-length-of-array-of-user-defined-types/17") + (check-next-stream-line-equal _test-output-stream " 59/pop-to-ecx" "F - test-convert-length-of-array-of-user-defined-types/18") + (check-next-stream-line-equal _test-output-stream " 58/pop-to-eax" "F - test-convert-length-of-array-of-user-defined-types/19") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ebx" "F - test-convert-length-of-array-of-user-defined-types/20") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-length-of-array-of-user-defined-types/21") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-length-of-array-of-user-defined-types/22") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-length-of-array-of-user-defined-types/23") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-length-of-array-of-user-defined-types/24") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-length-of-array-of-user-defined-types/25") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-length-of-array-of-user-defined-types/26") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-length-of-array-of-user-defined-types/27") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-index-with-non-array-atom-base-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: int\n") + (write _test-input-stream " var c/ecx: (addr int) <- index a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-index-with-non-array-atom-base-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-index-with-non-array-atom-base-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-index-with-non-array-compound-base-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (handle int)\n") + (write _test-input-stream " var c/ecx: (addr int) <- index a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-index-with-non-array-compound-base-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-index-with-non-array-compound-base-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-index-with-non-array-compound-base-type-2: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (addr int)\n") + (write _test-input-stream " var c/ecx: (addr int) <- index a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-index-with-non-array-compound-base-type-2: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-index-with-non-array-compound-base-type-2: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-index-with-array-atom-base-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: array\n") + (write _test-input-stream " var c/ecx: (addr int) <- index a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-index-with-array-atom-base-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-index-with-array-atom-base-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-index-with-addr-base-on-stack: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (addr array int)\n") + (write _test-input-stream " var c/ecx: (addr int) <- index a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-index-with-addr-base-on-stack: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-index-with-addr-base-on-stack: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-index-with-wrong-index-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a/eax: (addr array int) <- copy 0\n") + (write _test-input-stream " var b: boolean\n") + (write _test-input-stream " var c/ecx: (addr int) <- index a, b\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-index-with-wrong-index-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-index-with-wrong-index-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-index-with-offset-atom-index-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a/eax: (addr array int) <- copy 0\n") + (write _test-input-stream " var b: offset\n") + (write _test-input-stream " var c/ecx: (addr int) <- index a, b\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-index-with-offset-atom-index-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-index-with-offset-atom-index-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-index-with-offset-on-stack: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a/eax: (addr array int) <- copy 0\n") + (write _test-input-stream " var b: int\n") + (write _test-input-stream " var c/ecx: (addr int) <- index a, b\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-index-with-offset-on-stack: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-index-with-offset-on-stack: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-index-needs-offset-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a/eax: (addr array t) <- copy 0\n") + (write _test-input-stream " var b/ebx: int <- copy 0\n") + (write _test-input-stream " var c/ecx: (addr int) <- index a, b\n") + (write _test-input-stream "}\n") + (write _test-input-stream "type t {\n") # size 12 is not a power of two + (write _test-input-stream " x: int\n") + (write _test-input-stream " y: int\n") + (write _test-input-stream " z: int\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-index-needs-offset-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-index-needs-offset-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-index-with-output-not-address: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a/ebx: (addr array boolean) <- copy 0\n") + (write _test-input-stream " var o/edi: int <- index a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-index-with-output-not-address: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-index-with-output-not-address: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-index-with-output-not-address-2: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a/ebx: (addr array boolean) <- copy 0\n") + (write _test-input-stream " var o/edi: (int) <- index a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-index-with-output-not-address-2: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-index-with-output-not-address-2: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-index-with-wrong-output-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a/ebx: (addr array boolean) <- copy 0\n") + (write _test-input-stream " var o/edi: (addr int) <- index a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-index-with-wrong-output-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-index-with-wrong-output-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-index-with-wrong-output-compound-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a/ebx: (addr array handle boolean) <- copy 0\n") + (write _test-input-stream " var o/edi: (addr handle int) <- index a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-index-with-wrong-output-compound-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-index-with-wrong-output-compound-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-index-with-no-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var c/ecx: (addr int) <- index\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-index-with-no-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-index-with-no-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-index-with-too-few-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (array int 3)\n") + (write _test-input-stream " var c/ecx: (addr int) <- index a\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-index-with-too-few-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-index-with-too-few-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-index-with-too-many-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (array int 3)\n") + (write _test-input-stream " var c/ecx: (addr int) <- index a, 0, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-index-with-too-many-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-index-with-too-many-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-index-with-no-output: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (array int 3)\n") + (write _test-input-stream " index a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-index-with-no-output: output should be empty") + (check-next-stream-line-equal _test-error-stream "fn foo: stmt index: must have an output" "F - test-index-with-no-output: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-index-with-no-output: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-index-with-too-many-outputs: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (array int 3)\n") + (write _test-input-stream " var b/eax: (addr int) <- copy 0\n") + (write _test-input-stream " var c/ecx: (addr int) <- copy 0\n") + (write _test-input-stream " b, c <- index a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-index-with-too-many-outputs: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-index-with-too-many-outputs: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-compute-offset-with-non-array-atom-base-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: int\n") + (write _test-input-stream " var c/ecx: (offset int) <- compute-offset a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-compute-offset-with-non-array-atom-base-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-compute-offset-with-non-array-atom-base-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-compute-offset-with-non-array-compound-base-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (handle int)\n") + (write _test-input-stream " var c/ecx: (offset int) <- compute-offset a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-compute-offset-with-non-array-compound-base-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-compute-offset-with-non-array-compound-base-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-compute-offset-with-non-array-compound-base-type-2: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (addr int)\n") + (write _test-input-stream " var c/ecx: (offset int) <- compute-offset a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-compute-offset-with-non-array-compound-base-type-2: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-compute-offset-with-non-array-compound-base-type-2: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-compute-offset-with-array-atom-base-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: array\n") + (write _test-input-stream " var c/ecx: (offset int) <- compute-offset a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-compute-offset-with-array-atom-base-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-compute-offset-with-array-atom-base-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-compute-offset-with-wrong-index-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a/eax: (addr array int) <- copy 0\n") + (write _test-input-stream " var b: boolean\n") + (write _test-input-stream " var c/ecx: (offset int) <- compute-offset a, b\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-compute-offset-with-wrong-index-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-compute-offset-with-wrong-index-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-compute-offset-with-output-not-offset: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a/ebx: (addr array boolean) <- copy 0\n") + (write _test-input-stream " var o/edi: int <- compute-offset a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-compute-offset-with-output-not-offset: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-compute-offset-with-output-not-offset: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-compute-offset-with-output-not-address-2: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a/ebx: (addr array boolean) <- copy 0\n") + (write _test-input-stream " var o/edi: (int) <- compute-offset a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-compute-offset-with-output-not-address-2: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-compute-offset-with-output-not-address-2: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-compute-offset-with-wrong-output-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a/ebx: (addr array boolean) <- copy 0\n") + (write _test-input-stream " var o/edi: (offset int) <- compute-offset a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-compute-offset-with-wrong-output-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-compute-offset-with-wrong-output-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-compute-offset-with-wrong-output-compound-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a/ebx: (addr array handle boolean) <- copy 0\n") + (write _test-input-stream " var o/edi: (offset handle int) <- compute-offset a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-compute-offset-with-wrong-output-compound-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-compute-offset-with-wrong-output-compound-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-compute-offset-with-no-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var c/ecx: (offset int) <- compute-offset\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-compute-offset-with-no-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-compute-offset-with-no-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-compute-offset-with-too-few-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (array int 3)\n") + (write _test-input-stream " var c/ecx: (offset int) <- compute-offset a\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-compute-offset-with-too-few-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-compute-offset-with-too-few-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-compute-offset-with-too-many-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (array int 3)\n") + (write _test-input-stream " var c/ecx: (offset int) <- compute-offset a, 0, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-compute-offset-with-too-many-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-compute-offset-with-too-many-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-compute-offset-with-no-output: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (array int 3)\n") + (write _test-input-stream " compute-offset a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-compute-offset-with-no-output: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-compute-offset-with-no-output: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-compute-offset-with-too-many-outputs: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (array int 3)\n") + (write _test-input-stream " var b/eax: (offset int) <- compute-offset a, 0\n") + (write _test-input-stream " var c/ecx: (addr int) <- copy 0\n") + (write _test-input-stream " b, c <- compute-offset a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-compute-offset-with-too-many-outputs: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-compute-offset-with-too-many-outputs: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-read-from-stream: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var s/esi: (addr stream int) <- copy 0\n") + (write _test-input-stream " var o/ecx: (addr int) <- copy 0\n") + (write _test-input-stream " read-from-stream s, o\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-read-from-stream/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-read-from-stream/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-read-from-stream/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-read-from-stream/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-read-from-stream/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-read-from-stream/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %esi" "F - test-convert-read-from-stream/6") + (check-next-stream-line-equal _test-output-stream " be/copy-to-esi 0/imm32" "F - test-convert-read-from-stream/7") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-read-from-stream/8") + (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 0/imm32" "F - test-convert-read-from-stream/9") + (check-next-stream-line-equal _test-output-stream " (read-from-stream %esi %ecx 0x00000004)" "F - test-convert-read-from-stream/10") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-read-from-stream/11") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %esi" "F - test-convert-read-from-stream/12") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-read-from-stream/13") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-read-from-stream/14") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-read-from-stream/15") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-read-from-stream/16") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-read-from-stream/17") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-read-from-stream/18") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-read-from-stream-with-correct-payload-size: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var s/esi: (addr stream handle int) <- copy 0\n") + (write _test-input-stream " var o/ecx: (addr handle int) <- copy 0\n") + (write _test-input-stream " read-from-stream s, o\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-read-from-stream-with-correct-payload-size/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-read-from-stream-with-correct-payload-size/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-read-from-stream-with-correct-payload-size/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-read-from-stream-with-correct-payload-size/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-read-from-stream-with-correct-payload-size/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-read-from-stream-with-correct-payload-size/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %esi" "F - test-convert-read-from-stream-with-correct-payload-size/6") + (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") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-read-from-stream-with-correct-payload-size/8") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-read-from-stream-with-correct-payload-size/11") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %esi" "F - test-convert-read-from-stream-with-correct-payload-size/12") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-read-from-stream-with-correct-payload-size/13") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-read-from-stream-with-correct-payload-size/14") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-read-from-stream-with-correct-payload-size/15") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-read-from-stream-with-correct-payload-size/16") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-read-from-stream-with-correct-payload-size/17") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-read-from-stream-with-correct-payload-size/18") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-read-from-stream-with-non-stream-atom-base-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: int\n") + (write _test-input-stream " read-from-stream a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-read-from-stream-with-non-stream-atom-base-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-read-from-stream-with-non-stream-atom-base-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-read-from-stream-with-non-stream-compound-base-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (handle int)\n") + (write _test-input-stream " read-from-stream a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-read-from-stream-with-non-stream-compound-base-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-read-from-stream-with-non-stream-compound-base-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-read-from-stream-with-non-stream-compound-base-type-2: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (addr int)\n") + (write _test-input-stream " read-from-stream a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-read-from-stream-with-non-stream-compound-base-type-2: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-read-from-stream-with-non-stream-compound-base-type-2: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-read-from-stream-with-stream-atom-base-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: stream\n") + (write _test-input-stream " read-from-stream a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-read-from-stream-with-stream-atom-base-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-read-from-stream-with-stream-atom-base-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-read-from-stream-with-wrong-index-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a/eax: (addr stream int) <- copy 0\n") + (write _test-input-stream " var b: boolean\n") + (write _test-input-stream " read-from-stream a, b\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-read-from-stream-with-wrong-index-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-read-from-stream-with-wrong-index-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-read-from-stream-with-no-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " read-from-stream\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-read-from-stream-with-no-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-read-from-stream-with-no-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-read-from-stream-with-too-few-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (addr stream int)\n") + (write _test-input-stream " read-from-stream a\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-read-from-stream-with-too-few-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-read-from-stream-with-too-few-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-read-from-stream-with-too-many-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (addr stream int)\n") + (write _test-input-stream " var b: (addr int)\n") + (write _test-input-stream " read-from-stream a, b, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-read-from-stream-with-too-many-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-read-from-stream-with-too-many-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-read-from-stream-with-output: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (addr stream int)\n") + (write _test-input-stream " var b/eax: (addr int) <- copy 0\n") + (write _test-input-stream " b <- read-from-stream a, b\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-read-from-stream-with-output: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-read-from-stream-with-output: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-write-to-stream: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var s/esi: (addr stream int) <- copy 0\n") + (write _test-input-stream " var o/ecx: (addr int) <- copy 0\n") + (write _test-input-stream " write-to-stream s, o\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-write-to-stream/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-write-to-stream/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-write-to-stream/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-write-to-stream/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-write-to-stream/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-write-to-stream/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %esi" "F - test-convert-write-to-stream/6") + (check-next-stream-line-equal _test-output-stream " be/copy-to-esi 0/imm32" "F - test-convert-write-to-stream/7") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-write-to-stream/8") + (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 0/imm32" "F - test-convert-write-to-stream/9") + (check-next-stream-line-equal _test-output-stream " (write-to-stream %esi %ecx 0x00000004)" "F - test-convert-write-to-stream/10") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-write-to-stream/11") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %esi" "F - test-convert-write-to-stream/12") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-write-to-stream/13") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-write-to-stream/14") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-write-to-stream/15") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-write-to-stream/16") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-write-to-stream/17") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-write-to-stream/18") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-write-to-stream-with-correct-payload-size: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var s/esi: (addr stream handle int) <- copy 0\n") + (write _test-input-stream " var o/ecx: (addr handle int) <- copy 0\n") + (write _test-input-stream " write-to-stream s, o\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-write-to-stream-with-correct-payload-size/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-write-to-stream-with-correct-payload-size/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-write-to-stream-with-correct-payload-size/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-write-to-stream-with-correct-payload-size/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-write-to-stream-with-correct-payload-size/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-write-to-stream-with-correct-payload-size/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %esi" "F - test-convert-write-to-stream-with-correct-payload-size/6") + (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") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-write-to-stream-with-correct-payload-size/8") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-write-to-stream-with-correct-payload-size/11") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %esi" "F - test-convert-write-to-stream-with-correct-payload-size/12") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-write-to-stream-with-correct-payload-size/13") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-write-to-stream-with-correct-payload-size/14") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-write-to-stream-with-correct-payload-size/15") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-write-to-stream-with-correct-payload-size/16") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-write-to-stream-with-correct-payload-size/17") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-write-to-stream-with-correct-payload-size/18") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-write-to-stream-with-non-stream-atom-base-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: int\n") + (write _test-input-stream " write-to-stream a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-write-to-stream-with-non-stream-atom-base-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-write-to-stream-with-non-stream-atom-base-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-write-to-stream-with-non-stream-compound-base-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (handle int)\n") + (write _test-input-stream " write-to-stream a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-write-to-stream-with-non-stream-compound-base-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-write-to-stream-with-non-stream-compound-base-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-write-to-stream-with-non-stream-compound-base-type-2: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (addr int)\n") + (write _test-input-stream " write-to-stream a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-write-to-stream-with-non-stream-compound-base-type-2: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-write-to-stream-with-non-stream-compound-base-type-2: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-write-to-stream-with-stream-atom-base-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: stream\n") + (write _test-input-stream " write-to-stream a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-write-to-stream-with-stream-atom-base-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-write-to-stream-with-stream-atom-base-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-write-to-stream-with-wrong-index-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a/eax: (addr stream int) <- copy 0\n") + (write _test-input-stream " var b: boolean\n") + (write _test-input-stream " write-to-stream a, b\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-write-to-stream-with-wrong-index-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-write-to-stream-with-wrong-index-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-write-to-stream-with-no-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " write-to-stream\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-write-to-stream-with-no-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-write-to-stream-with-no-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-write-to-stream-with-too-few-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (addr stream int)\n") + (write _test-input-stream " write-to-stream a\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-write-to-stream-with-too-few-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-write-to-stream-with-too-few-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-write-to-stream-with-too-many-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (addr stream int)\n") + (write _test-input-stream " var b: (addr int)\n") + (write _test-input-stream " write-to-stream a, b, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-write-to-stream-with-too-many-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-write-to-stream-with-too-many-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-write-to-stream-with-output: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (addr stream int)\n") + (write _test-input-stream " var b/eax: (addr int) <- copy 0\n") + (write _test-input-stream " b <- write-to-stream a, b\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-write-to-stream-with-output: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-write-to-stream-with-output: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-length-with-non-array-atom-base-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: int\n") + (write _test-input-stream " var c/ecx: int <- length a\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-length-with-non-array-atom-base-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-length-with-non-array-atom-base-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-length-with-non-array-compound-base-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (handle int)\n") + (write _test-input-stream " var c/ecx: (addr int) <- length a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-length-with-non-array-compound-base-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-length-with-non-array-compound-base-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-length-with-non-array-compound-base-type-2: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (addr int)\n") + (write _test-input-stream " var c/ecx: (addr int) <- length a, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-length-with-non-array-compound-base-type-2: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-length-with-non-array-compound-base-type-2: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-length-with-array-atom-base-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: array\n") + (write _test-input-stream " var c/ecx: (addr int) <- length a\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-length-with-array-atom-base-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-length-with-array-atom-base-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-length-with-addr-base-on-stack: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (addr array int)\n") + (write _test-input-stream " var c/ecx: (addr int) <- length a\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-length-with-addr-base-on-stack: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-length-with-addr-base-on-stack: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-length-with-wrong-output-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a/ebx: (addr array boolean) <- copy 0\n") + (write _test-input-stream " var o/edi: (addr int) <- length a\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-length-with-wrong-output-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-length-with-wrong-output-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-length-with-wrong-output-compound-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a/ebx: (addr array handle boolean) <- copy 0\n") + (write _test-input-stream " var o/edi: (addr handle int) <- length a\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-length-with-wrong-output-compound-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-length-with-wrong-output-compound-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-length-with-no-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var c/ecx: int <- length\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-length-with-no-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-length-with-no-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-length-with-too-many-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (array int 3)\n") + (write _test-input-stream " var c/ecx: int <- length a, 0, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-length-with-too-many-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-length-with-too-many-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-length-with-no-output: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (array int 3)\n") + (write _test-input-stream " length a\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-length-with-no-output: output should be empty") + (check-next-stream-line-equal _test-error-stream "fn foo: stmt length: must have an output" "F - test-length-with-no-output: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-length-with-no-output: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-length-with-too-many-outputs: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var a: (array int 3)\n") + (write _test-input-stream " var b/eax: int <- copy 0\n") + (write _test-input-stream " var c/ecx: int <- copy 0\n") + (write _test-input-stream " b, c <- length a\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-length-with-too-many-outputs: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-length-with-too-many-outputs: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-function-with-return-register-and-local: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo -> _/eax: int {\n") + (write _test-input-stream " var y/eax: int <- copy 3\n") + (write _test-input-stream " var z/ecx: int <- copy 4\n") + (write _test-input-stream " return y\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-return-register-and-local/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-return-register-and-local/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-return-register-and-local/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-return-register-and-local/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-return-register-and-local/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-return-register-and-local/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-function-with-return-register-and-local/6") + (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 3/imm32" "F - test-convert-function-with-return-register-and-local/7") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-function-with-return-register-and-local/8") + (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 4/imm32" "F - test-convert-function-with-return-register-and-local/9") + (check-next-stream-line-equal _test-output-stream " 8b/-> %eax 0x00000000/r32" "F - test-convert-function-with-return-register-and-local/10") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-function-with-return-register-and-local/11") + (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") + (check-next-stream-line-equal _test-output-stream " e9/jump $foo:0x00000001:break/disp32" "F - test-convert-function-with-return-register-and-local/13") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-return-register-and-local/14") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-return-register-and-local/15") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-return-register-and-local/16") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-return-register-and-local/17") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-return-register-and-local/18") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-return-register-and-local/19") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-return-register-and-local-2: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo -> _/eax: int {\n") + (write _test-input-stream " var y/eax: int <- copy 3\n") + (write _test-input-stream " var z/ecx: int <- copy 4\n") + (write _test-input-stream " return z\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-return-register-and-local-2/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-return-register-and-local-2/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-return-register-and-local-2/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-return-register-and-local-2/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-return-register-and-local-2/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-return-register-and-local-2/5") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-function-with-return-register-and-local-2/6") + (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") + (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-function-with-return-register-and-local-2/8") + (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") + (check-next-stream-line-equal _test-output-stream " 8b/-> %ecx 0x00000000/r32" "F - test-convert-function-with-return-register-and-local-2/10") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-function-with-return-register-and-local-2/11") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-return-register-and-local-2/14") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-return-register-and-local-2/15") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-return-register-and-local-2/16") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-return-register-and-local-2/17") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-return-register-and-local-2/18") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-return-register-and-local-2/19") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-return-float-register-and-local: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo -> _/xmm1: float {\n") + (write _test-input-stream " var y/eax: int <- copy 3\n") + (write _test-input-stream " var g/xmm0: float <- convert y\n") + (write _test-input-stream " var h/xmm1: float <- convert y\n") + (write _test-input-stream " return g\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-return-float-register-and-local/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-return-float-register-and-local/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-return-float-register-and-local/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-return-float-register-and-local/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-return-float-register-and-local/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-return-float-register-and-local/5") + (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 + (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") + (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 + (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") + (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") + (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 + (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") + (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") + (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 + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 4/imm32" "F - test-convert-floating-point-dereferenced/15") # reclaim h + (check-next-stream-line-equal _test-output-stream " f3 0f 10/-> *esp 0/x32" "F - test-convert-floating-point-dereferenced/16") # reclaim g + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 4/imm32" "F - test-convert-floating-point-dereferenced/17") + (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 + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-return-float-register-and-local/20") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-return-float-register-and-local/21") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-return-float-register-and-local/22") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-return-float-register-and-local/23") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-return-float-register-and-local/24") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-return-float-register-and-local/25") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-convert-function-with-return-and-local-vars: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo -> _/eax: int {\n") + (write _test-input-stream " {\n") + (write _test-input-stream " var x: int\n") + (write _test-input-stream " {\n") + (write _test-input-stream " var y: int\n") + (write _test-input-stream " return y\n") + (write _test-input-stream " increment x\n") + (write _test-input-stream " }\n") + (write _test-input-stream " }\n") + (write _test-input-stream " return 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-return-and-local-vars/0") + (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-return-and-local-vars/1") + (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-return-and-local-vars/2") + (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-return-and-local-vars/3") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-return-and-local-vars/4") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-return-and-local-vars/5") + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-return-and-local-vars/6") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-return-and-local-vars/7") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-return-and-local-vars/8") # var x + (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-return-and-local-vars/9") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:" "F - test-convert-function-with-return-and-local-vars/10") + (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-return-and-local-vars/11") # var y + (check-next-stream-line-equal _test-output-stream " 8b/-> *(ebp+0xfffffff8) 0x00000000/r32" "F - test-convert-function-with-return-and-local-vars/12") + (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") + (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") + (check-next-stream-line-equal _test-output-stream " e9/jump $foo:0x00000001:break/disp32" "F - test-convert-function-with-return-and-local-vars/15") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-return-and-local-vars/16") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:" "F - test-convert-function-with-return-and-local-vars/17") + (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") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-return-and-local-vars/19") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-return-and-local-vars/20") + (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") + (check-next-stream-line-equal _test-output-stream " e9/jump $foo:0x00000001:break/disp32" "F - test-convert-function-with-return-and-local-vars/21") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-return-and-local-vars/21") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-return-and-local-vars/22") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-return-and-local-vars/23") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-return-and-local-vars/24") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-return-and-local-vars/25") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-return-and-local-vars/26") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-copy-object-with-no-inout: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " copy-object\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-object-with-no-inout: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-object-with-no-inout: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-object-with-no-source: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: (addr int)\n") + (write _test-input-stream " copy-object x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-object-with-no-source: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-object-with-no-source: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-object-with-too-many-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: (addr boolean)\n") + (write _test-input-stream " copy-object x, x, x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-object-with-too-many-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-object-with-too-many-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-object-with-output: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: (addr boolean) <- copy 0\n") + (write _test-input-stream " var y/ecx: (addr boolean) <- copy 0\n") + (write _test-input-stream " x <- copy-object x, y\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-object-with-output: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-object-with-output: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-object-deref-address: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: (addr int) <- copy 0\n") + (write _test-input-stream " var y/ecx: (addr addr int) <- copy 0\n") + (write _test-input-stream " copy-object *y, x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) + # no errors + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-object-non-addr: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: int\n") + (write _test-input-stream " var y: int\n") + (write _test-input-stream " copy-object y, x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-object-non-addr: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-object-non-addr: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-copy-object-non-equal: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: (addr int)\n") + (write _test-input-stream " var y: (addr boolean)\n") + (write _test-input-stream " copy-object y, x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-copy-object-non-equal: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-copy-object-non-equal: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-allocate-with-no-inout: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " allocate\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-allocate-with-no-inout: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-allocate-with-no-inout: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-allocate-with-too-many-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: (addr handle int)\n") + (write _test-input-stream " allocate x, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-allocate-with-too-many-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-allocate-with-too-many-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-allocate-with-output: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: boolean <- copy 0\n") + (write _test-input-stream " var y/ecx: (addr handle int) <- copy 0\n") + (write _test-input-stream " x <- allocate y\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-allocate-with-output: output should be empty") + (check-next-stream-line-equal _test-error-stream "fn foo: stmt 'allocate' must not have any outputs" "F - test-allocate-with-output: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-allocate-with-output: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-allocate-non-addr: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var y: (handle int)\n") + (write _test-input-stream " allocate y\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-allocate-non-addr: output must be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-allocate-non-addr: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-allocate-non-addr-handle: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var y/ecx: (addr int) <- copy 0\n") + (write _test-input-stream " allocate y\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-allocate-non-addr-handle: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-allocate-non-addr-handle: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-allocate-deref-address: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var y/ecx: (addr addr handle int) <- copy 0\n") + (write _test-input-stream " allocate *y\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) + # no errors + # . epilogue + 5d/pop-to-ebp + c3/return + +test-populate-with-no-inout: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " populate\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-populate-with-no-inout: output should be empty") + (check-next-stream-line-equal _test-error-stream "fn foo: stmt 'populate' must have two inouts" "F - test-populate-with-no-inout: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-populate-with-no-inout: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-populate-with-too-many-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: (addr handle int)\n") + (write _test-input-stream " populate x, 3, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-populate-with-too-many-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-populate-with-too-many-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-populate-with-output: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: boolean <- copy 0\n") + (write _test-input-stream " var y/ecx: (addr handle int) <- copy 0\n") + (write _test-input-stream " x <- populate y\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-populate-with-output: output should be empty") + (check-next-stream-line-equal _test-error-stream "fn foo: stmt 'populate' must not have any outputs" "F - test-populate-with-output: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-populate-with-output: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-populate-non-addr: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var y: (handle int)\n") + (write _test-input-stream " populate y, 3\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-populate-non-addr: output must be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-populate-non-addr: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-populate-non-addr-handle: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var y/ecx: (addr int) <- copy 0\n") + (write _test-input-stream " populate y, 3\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-populate-non-addr-handle: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-populate-non-addr-handle: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-populate-non-addr-handle-array: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var y/ecx: (addr handle int) <- copy 0\n") + (write _test-input-stream " populate y, 3\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-populate-non-addr-handle-array: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-populate-non-addr-handle-array: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-populate-deref-address: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var y/ecx: (addr addr handle array int) <- copy 0\n") + (write _test-input-stream " populate *y, 3\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) + # no errors + # . epilogue + 5d/pop-to-ebp + c3/return + +test-populate-stream-with-no-inout: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " populate-stream\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-populate-stream-with-no-inout: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-populate-stream-with-no-inout: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-populate-stream-with-too-many-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: (addr handle int)\n") + (write _test-input-stream " populate-stream x, 3, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-populate-stream-with-too-many-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-populate-stream-with-too-many-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-populate-stream-with-output: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: boolean <- copy 0\n") + (write _test-input-stream " var y/ecx: (addr handle int) <- copy 0\n") + (write _test-input-stream " x <- populate-stream y\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-populate-stream-with-output: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-populate-stream-with-output: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-populate-stream-non-addr: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var y: (handle int)\n") + (write _test-input-stream " populate-stream y, 3\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-populate-stream-non-addr: output must be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-populate-stream-non-addr: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-populate-stream-non-addr-handle: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var y/ecx: (addr int) <- copy 0\n") + (write _test-input-stream " populate-stream y, 3\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-populate-stream-non-addr-handle: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-populate-stream-non-addr-handle: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-populate-stream-non-addr-handle-stream: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var y/ecx: (addr handle int) <- copy 0\n") + (write _test-input-stream " populate-stream y, 3\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-populate-stream-non-addr-handle-stream: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-populate-stream-non-addr-handle-stream: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-populate-stream-deref-address: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var y/ecx: (addr addr handle stream int) <- copy 0\n") + (write _test-input-stream " populate-stream *y, 3\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) + # no errors + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-with-no-inout: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: int <- convert\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-convert-with-no-inout: output should be empty") + (check-next-stream-line-equal _test-error-stream "fn foo: stmt 'convert' expects an inout" "F - test-convert-with-no-inout: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-convert-with-no-inout: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-with-multiple-inouts: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: int <- convert 0, 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-convert-with-multiple-inouts: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-convert-with-multiple-inouts: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-with-no-output: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " convert 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-convert-with-no-output: output should be empty") + (check-next-stream-line-equal _test-error-stream "fn foo: stmt 'convert' expects an output" "F - test-convert-with-no-output: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-convert-with-no-output: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-with-multiple-outputs: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: int <- copy 0\n") + (write _test-input-stream " var y/ecx: int <- copy 0\n") + (write _test-input-stream " x, y <- convert 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-convert-with-multiple-outputs: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-convert-with-multiple-outputs: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-deref-address: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x/eax: (addr int) <- copy 0\n") + (write _test-input-stream " var y/xmm4: float <- convert *x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0) + (flush _test-output-buffered-file) + # no errors + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-to-non-register: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: float\n") + (write _test-input-stream " var y: int\n") + (write _test-input-stream " x <- convert y\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-convert-to-non-register: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-convert-to-non-register: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-invalid-inout-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: boolean\n") + (write _test-input-stream " var y/xmm1: float <- convert x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-convert-invalid-inout-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-convert-invalid-inout-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-invalid-output-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: float\n") + (write _test-input-stream " var y/eax: boolean <- convert x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-convert-invalid-output-type: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-convert-invalid-output-type: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-int-to-int: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: int\n") + (write _test-input-stream " var y/eax: int <- convert x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-convert-int-to-int: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-convert-int-to-int: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +test-convert-float-to-float: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-input-stream) + (clear-stream $_test-input-buffered-file->buffer) + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo {\n") + (write _test-input-stream " var x: float\n") + (write _test-input-stream " var y/xmm6: float <- convert x\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-convert-float-to-float: output should be empty") + (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") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-convert-float-to-float: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + +####################################################### +# Parsing +####################################################### + +== data + +# Global state added to each var record when parsing a function +Next-block-index: # (addr int) + 1/imm32 + +Curr-block-depth: # (addr int) + 1/imm32 + +== code + +parse-mu: # in: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor) + # pseudocode + # var curr-function: (addr handle function) = Program->functions + # var curr-signature: (addr handle function) = Program->signatures + # var curr-type: (addr handle typeinfo) = Program->types + # var line: (stream byte 512) + # var word-slice: slice + # while true # line loop + # clear-stream(line) + # read-line-buffered(in, line) + # if (line->write == 0) break # end of file + # word-slice = next-mu-token(line) + # if slice-empty?(word-slice) # end of line + # continue + # else if slice-starts-with?(word-slice, "#") # comment + # continue # end of line + # else if slice-equal?(word-slice, "fn") + # var new-function: (handle function) = allocate(function) + # var vars: (stack live-var 256) + # populate-mu-function-header(line, new-function, vars) + # populate-mu-function-body(in, new-function, vars) + # assert(vars->top == 0) + # *curr-function = new-function + # curr-function = &new-function->next + # else if slice-equal?(word-slice, "sig") + # var new-function: (handle function) = allocate(function) + # populate-mu-function-signature(line, new-function) + # *curr-signature = new-function + # curr-signature = &new-function->next + # else if slice-equal?(word-slice, "type") + # word-slice = next-mu-token(line) + # type-id = pos-or-insert-slice(Type-id, word-slice) + # var new-type: (handle typeinfo) = find-or-create-typeinfo(type-id) + # assert(next-word(line) == "{") + # populate-mu-type(in, new-type) + # else + # abort() + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # var curr-signature: (addr handle function) at *(ebp-4) + 68/push _Program-signatures/imm32 + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + 57/push-edi + # var line/ecx: (stream byte 512) + 81 5/subop/subtract %esp 0x200/imm32 + 68/push 0x200/imm32/size + 68/push 0/imm32/read + 68/push 0/imm32/write + 89/<- %ecx 4/r32/esp + # var word-slice/edx: slice + 68/push 0/imm32/end + 68/push 0/imm32/start + 89/<- %edx 4/r32/esp + # var curr-function/edi: (addr handle function) + bf/copy-to-edi _Program-functions/imm32 + # var vars/ebx: (stack live-var 256) + 81 5/subop/subtract %esp 0xc00/imm32 + 68/push 0xc00/imm32/size + 68/push 0/imm32/top + 89/<- %ebx 4/r32/esp + { +$parse-mu:line-loop: + (clear-stream %ecx) + (read-line-buffered *(ebp+8) %ecx) + # if (line->write == 0) break + 81 7/subop/compare *ecx 0/imm32 + 0f 84/jump-if-= break/disp32 +#? # dump line {{{ +#? (write 2 "parse-mu: ^") +#? (write-stream 2 %ecx) +#? (write 2 "$\n") +#? (rewind-stream %ecx) +#? # }}} + (next-mu-token %ecx %edx) + # if slice-empty?(word-slice) continue + (slice-empty? %edx) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= loop/disp32 + # if (*word-slice->start == "#") continue + # . eax = *word-slice->start + 8b/-> *edx 0/r32/eax + 8a/copy-byte *eax 0/r32/AL + 81 4/subop/and %eax 0xff/imm32 + # . if (eax == '#') continue + 3d/compare-eax-and 0x23/imm32/hash + 0f 84/jump-if-= loop/disp32 + # if (slice-equal?(word-slice, "fn")) parse a function + { +$parse-mu:fn: + (slice-equal? %edx "fn") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= break/disp32 + # var new-function/esi: (handle function) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %esi 4/r32/esp + # populate-mu-function(line, in, vars, new-function) + (allocate Heap *Function-size %esi) + # var new-function-addr/eax: (addr function) + (lookup *esi *(esi+4)) # => eax + # initialize vars + (clear-stack %ebx) + # + (populate-mu-function-header %ecx %eax %ebx *(ebp+0xc) *(ebp+0x10)) + (populate-mu-function-body *(ebp+8) %eax %ebx *(ebp+0xc) *(ebp+0x10)) + # *curr-function = new-function + 8b/-> *esi 0/r32/eax + 89/<- *edi 0/r32/eax + 8b/-> *(esi+4) 0/r32/eax + 89/<- *(edi+4) 0/r32/eax + # curr-function = &new-function->next + # . var tmp/eax: (addr function) = lookup(new-function) + (lookup *esi *(esi+4)) # => eax + # . curr-function = &tmp->next + 8d/copy-address *(eax+0x20) 7/r32/edi # Function-next + # reclaim new-function + 81 0/subop/add %esp 8/imm32 + # + e9/jump $parse-mu:line-loop/disp32 + } + # if (slice-equal?(word-slice, "sig")) parse a function signature + # Function signatures are for providing types to SubX functions. + { +$parse-mu:sig: + (slice-equal? %edx "sig") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= break/disp32 + # edi = curr-function + 57/push-edi + 8b/-> *(ebp-4) 7/r32/edi + # var new-function/esi: (handle function) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %esi 4/r32/esp + # populate-mu-function(line, in, vars, new-function) + (allocate Heap *Function-size %esi) + # var new-function-addr/eax: (addr function) + (lookup *esi *(esi+4)) # => eax + # + (populate-mu-function-signature %ecx %eax *(ebp+0xc) *(ebp+0x10)) + # *curr-signature = new-function + 8b/-> *esi 0/r32/eax + 89/<- *edi 0/r32/eax + 8b/-> *(esi+4) 0/r32/eax + 89/<- *(edi+4) 0/r32/eax + # curr-signature = &new-function->next + # . var tmp/eax: (addr function) = lookup(new-function) + (lookup *esi *(esi+4)) # => eax + # . curr-function = &tmp->next + 8d/copy-address *(eax+0x20) 7/r32/edi # Function-next + # reclaim new-function + 81 0/subop/add %esp 8/imm32 + # save curr-function + 89/<- *(ebp-4) 7/r32/edi + # restore edi + 5f/pop-to-edi + # + e9/jump $parse-mu:line-loop/disp32 + } + # if (slice-equal?(word-slice, "type")) parse a type (struct/record) definition + { +$parse-mu:type: + (slice-equal? %edx "type") # => eax + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= break/disp32 + (next-mu-token %ecx %edx) + # var type-id/eax: int + (pos-or-insert-slice Type-id %edx) # => eax + # spill + 51/push-ecx + # var new-type/ecx: (handle typeinfo) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %ecx 4/r32/esp + (find-or-create-typeinfo %eax %ecx) + # + (lookup *ecx *(ecx+4)) # => eax + # TODO: ensure that 'line' has nothing else but '{' +#? (dump-typeinfos "=== aaa\n") + (populate-mu-type *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10)) # => eax +#? (dump-typeinfos "=== zzz\n") + # reclaim new-type + 81 0/subop/add %esp 8/imm32 + # restore + 59/pop-to-ecx + e9/jump $parse-mu:line-loop/disp32 + } + # otherwise abort + e9/jump $parse-mu:error1/disp32 + } # end line loop +$parse-mu:end: + # . reclaim locals + 81 0/subop/add %esp 0x20c/imm32 # line + 81 0/subop/add %esp 0xc08/imm32 # vars + 81 0/subop/add %esp 8/imm32 + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . reclaim local + 81 0/subop/add %esp 4/imm32 + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$parse-mu:error1: + # error("unexpected top-level command: " word-slice "\n") + (write-buffered *(ebp+0xc) "unexpected top-level command: ") + (write-slice-buffered *(ebp+0xc) %edx) + (write-buffered *(ebp+0xc) "\n") + (flush *(ebp+0xc)) + (stop *(ebp+0x10) 1) + # never gets here + +$parse-mu:error2: + # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n") + (write-int32-hex-buffered *(ebp+0xc) *ebx) + (write-buffered *(ebp+0xc) " vars not reclaimed after fn '") + (write-slice-buffered *(ebp+0xc) *eax) # Function-name + (write-buffered *(ebp+0xc) "'\n") + (flush *(ebp+0xc)) + (stop *(ebp+0x10) 1) + # never gets here + +# scenarios considered: +# ✗ fn foo # no block +# ✓ fn foo { +# ✗ fn foo { { +# ✗ fn foo { } +# ✗ fn foo { } { +# ✗ fn foo x { +# ✗ fn foo x: { +# ✓ fn foo x: int { +# ✓ fn foo x: int { +# ✓ fn foo x: int -> _/eax: int { +# TODO: +# disallow outputs of type `(... addr ...)` +# disallow inputs of type `(... addr ... addr ...)` +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) + # pseudocode: + # var word-slice: slice + # next-mu-token(first-line, word-slice) + # if slice-empty?(word-slice) abort + # assert(word-slice not in '{' '}' '->') + # out->name = slice-to-string(word-slice) + # ## inouts + # while true + # word-slice = next-mu-token(first-line) + # if slice-empty?(word-slice) abort + # if (word-slice == '{') goto done + # if (word-slice == '->') break + # assert(word-slice != '}') + # var v: (handle var) = parse-var-with-type(word-slice, first-line) + # assert(v->register == null) + # # v->block-depth is implicitly 0 + # out->inouts = append(v, out->inouts) + # push(vars, {v, false}) + # ## outputs + # while true + # word-slice = next-mu-token(first-line) + # if slice-empty?(word-slice) abort + # if (word-slice == '{') break + # assert(word-slice not in '}' '->') + # var v: (handle var) = parse-var-with-type(word-slice, first-line) + # assert(v->register != null) + # assert(v->name == "_") + # out->outputs = append(v, out->outputs) + # done: + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 57/push-edi + # edi = out + 8b/-> *(ebp+0xc) 7/r32/edi + # var word-slice/ecx: slice + 68/push 0/imm32/end + 68/push 0/imm32/start + 89/<- %ecx 4/r32/esp + # var v/ebx: (handle var) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %ebx 4/r32/esp + # read function name + (next-mu-token *(ebp+8) %ecx) + # error checking + # if slice-empty?(word-slice) abort + (slice-empty? %ecx) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 + # if (word-slice == '{') abort + (slice-equal? %ecx "{") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 + # if (word-slice == '->') abort + (slice-equal? %ecx "->") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 + # if (word-slice == '}') abort + (slice-equal? %ecx "}") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 + # if word-slice already defined, abort + (function-exists? %ecx) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-header:error-duplicate/disp32 + # + (slice-starts-with? %ecx "break") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-header:error-break/disp32 + (slice-starts-with? %ecx "loop") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-header:error-loop/disp32 + (slice-equal? %ecx "lookup") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-header:error-lookup/disp32 + # save function name + (slice-to-string Heap %ecx %edi) # Function-name + # save function inouts + { +$populate-mu-function-header:check-for-inout: + (next-mu-token *(ebp+8) %ecx) + # if slice-empty?(word-slice) abort + (slice-empty? %ecx) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 + # if (word-slice == '{') goto done + (slice-equal? %ecx "{") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-header:done/disp32 + # if (word-slice == '->') break + (slice-equal? %ecx "->") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= break/disp32 + # if (word-slice == '}') abort + (slice-equal? %ecx "}") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 + # v = parse-var-with-type(word-slice, first-line) + (lookup *edi *(edi+4)) # Function-name Function-name => eax + (parse-var-with-type %ecx *(ebp+8) %ebx %eax *(ebp+0x14) *(ebp+0x18)) + # if (v->register != null) abort + # . eax: (addr var) = lookup(v) + (lookup *ebx *(ebx+4)) # => eax + 81 7/subop/compare *(eax+0x18) 0/imm32 # Var-register + 0f 85/jump-if-!= $populate-mu-function-header:error2/disp32 + # if function name is not "main" + # and v->type contains an 'addr' anywhere except the start, abort + { + (lookup *edi *(edi+4)) # Function-name Function-name => eax + (string-equal? %eax "main") # => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 + (lookup *ebx *(ebx+4)) # => eax + (addr-payload-contains-addr? %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-header:error-nested-addr-inout/disp32 + } + # v->block-depth is implicitly 0 + # + # out->inouts = append(v, out->inouts) + 8d/copy-address *(edi+8) 0/r32/eax # Function-inouts + (append-list Heap *ebx *(ebx+4) *(edi+8) *(edi+0xc) %eax) # Function-inouts, Function-inouts + # push(vars, {v, false}) + (push *(ebp+0x10) *ebx) + (push *(ebp+0x10) *(ebx+4)) + (push *(ebp+0x10) 0) # false + # + e9/jump loop/disp32 + } + # save function outputs + { +$populate-mu-function-header:check-for-out: + (next-mu-token *(ebp+8) %ecx) + # if slice-empty?(word-slice) abort + (slice-empty? %ecx) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 + # if (word-slice == '{') break + (slice-equal? %ecx "{") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= break/disp32 + # if (word-slice == '->') abort + (slice-equal? %ecx "->") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 + # if (word-slice == '}') abort + (slice-equal? %ecx "}") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 + # v = parse-var-with-type(word-slice, first-line) + (lookup *edi *(edi+4)) # Function-name Function-name => eax + (parse-var-with-type %ecx *(ebp+8) %ebx %eax *(ebp+0x14) *(ebp+0x18)) + # assert(var->register != null) + # . eax: (addr var) = lookup(v) + (lookup *ebx *(ebx+4)) # => eax + 81 7/subop/compare *(eax+0x18) 0/imm32 # Var-register + 0f 84/jump-if-= $populate-mu-function-header:error3/disp32 + # if (var->name != "_") abort + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (string-equal? %eax "_") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $populate-mu-function-header:error4/disp32 + # if v->type is an addr, abort + (lookup *ebx *(ebx+4)) # => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + (is-mu-addr-type? %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-header:error-addr-output/disp32 + # out->outputs = append(v, out->outputs) + 8d/copy-address *(edi+0x10) 0/r32/eax # Function-outputs + (append-list Heap *ebx *(ebx+4) *(edi+0x10) *(edi+0x14) %eax) # Function-outputs, Function-outputs + # + e9/jump loop/disp32 + } +$populate-mu-function-header:done: + (check-no-tokens-left *(ebp+8)) +$populate-mu-function-header:end: + # . reclaim locals + 81 0/subop/add %esp 0x10/imm32 + # . restore registers + 5f/pop-to-edi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$populate-mu-function-header:error1: + # error("function header not in form 'fn <name> {'") + (write-buffered *(ebp+0x14) "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '") + (flush *(ebp+0x14)) + (rewind-stream *(ebp+8)) + (write-stream-data *(ebp+0x14) *(ebp+8)) + (write-buffered *(ebp+0x14) "'\n") + (flush *(ebp+0x14)) + (stop *(ebp+0x18) 1) + # never gets here + +$populate-mu-function-header:error2: + # error("fn " fn ": function inout '" var "' cannot be in a register") + (write-buffered *(ebp+0x14) "fn ") + 50/push-eax + (lookup *edi *(edi+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x14) %eax) + 58/pop-to-eax + (write-buffered *(ebp+0x14) ": function inout '") + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x14) %eax) + (write-buffered *(ebp+0x14) "' cannot be in a register") + (flush *(ebp+0x14)) + (stop *(ebp+0x18) 1) + # never gets here + +$populate-mu-function-header:error3: + # error("fn " fn ": function output '" var "' must be in a register") + (write-buffered *(ebp+0x14) "fn ") + 50/push-eax + (lookup *edi *(edi+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x14) %eax) + 58/pop-to-eax + (write-buffered *(ebp+0x14) ": function output '") + (lookup *ebx *(ebx+4)) # => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x14) %eax) + (write-buffered *(ebp+0x14) "' must be in a register, in instruction '") + (rewind-stream *(ebp+8)) + (write-stream-data *(ebp+0x14) *(ebp+8)) + (write-buffered *(ebp+0x14) "'\n") + (flush *(ebp+0x14)) + (stop *(ebp+0x18) 1) + # never gets here + +$populate-mu-function-header:error4: + # error("fn " fn ": function outputs cannot be named; rename '" var "' in the header to '_'") + (write-buffered *(ebp+0x14) "fn ") + 50/push-eax + (lookup *edi *(edi+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x14) %eax) + 58/pop-to-eax + (write-buffered *(ebp+0x14) ": function outputs cannot be named; rename '") + (lookup *ebx *(ebx+4)) # => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x14) %eax) + (write-buffered *(ebp+0x14) "' in the header to '_'\n") + (flush *(ebp+0x14)) + (stop *(ebp+0x18) 1) + # never gets here + +$populate-mu-function-header:error-duplicate: + (write-buffered *(ebp+0x14) "fn ") + (write-slice-buffered *(ebp+0x14) %ecx) + (write-buffered *(ebp+0x14) " defined more than once\n") + (flush *(ebp+0x14)) + (stop *(ebp+0x18) 1) + # never gets here + +$populate-mu-function-header:error-break: + (write-buffered *(ebp+0x14) "Sorry, I've reserved all function names starting with 'break' for now. Please contact mu@akkartik.com.\n") + (flush *(ebp+0x14)) + (stop *(ebp+0x18) 1) + # never gets here + +$populate-mu-function-header:error-loop: + (write-buffered *(ebp+0x14) "Sorry, I've reserved all function names starting with 'loop' for now. Please contact mu@akkartik.com.\n") + (flush *(ebp+0x14)) + (stop *(ebp+0x18) 1) + # never gets here + +$populate-mu-function-header:error-lookup: + (write-buffered *(ebp+0x14) "cannot define a function called 'lookup'\n") + (flush *(ebp+0x14)) + (stop *(ebp+0x18) 1) + # never gets here + +$populate-mu-function-header:error-addr-output: + # error("fn " fn ": output cannot have an addr type; that could allow unsafe addresses to escape the function") + (write-buffered *(ebp+0x14) "fn ") + 50/push-eax + (lookup *edi *(edi+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x14) %eax) + 58/pop-to-eax + (write-buffered *(ebp+0x14) ": output cannot have an addr type; that could allow unsafe addresses to escape the function\n") + (flush *(ebp+0x14)) + (stop *(ebp+0x18) 1) + # never gets here + +$populate-mu-function-header:error-nested-addr-inout: + # 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") + (write-buffered *(ebp+0x14) "fn ") + (lookup *edi *(edi+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x14) %eax) + (write-buffered *(ebp+0x14) ": inout '") + (lookup *ebx *(ebx+4)) # => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x14) %eax) + (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") + (flush *(ebp+0x14)) + (stop *(ebp+0x18) 1) + # never gets here + +# scenarios considered: +# ✓ fn foo +# ✗ fn foo { +# ✓ fn foo x +# ✓ fn foo x: int +# ✓ fn foo x: int -> _/eax: int +# TODO: +# disallow outputs of type `(... addr ...)` +# disallow inputs of type `(... addr ... addr ...)` +populate-mu-function-signature: # first-line: (addr stream byte), out: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # pseudocode: + # var word-slice: slice + # next-mu-token(first-line, word-slice) + # assert(word-slice not in '{' '}' '->') + # out->name = slice-to-string(word-slice) + # ## inouts + # while true + # word-slice = next-mu-token(first-line) + # if slice-empty?(word-slice) break + # if (word-slice == '->') break + # assert(word-slice not in '{' '}') + # var v: (handle var) = parse-var-with-type(word-slice, first-line) + # assert(v->register == null) + # # v->block-depth is implicitly 0 + # out->inouts = append(v, out->inouts) + # ## outputs + # while true + # word-slice = next-mu-token(first-line) + # if slice-empty?(word-slice) break + # assert(word-slice not in '{' '}' '->') + # var v: (handle var) = parse-var-with-type(word-slice, first-line) + # assert(v->register != null) + # out->outputs = append(v, out->outputs) + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 57/push-edi + # edi = out + 8b/-> *(ebp+0xc) 7/r32/edi + # var word-slice/ecx: slice + 68/push 0/imm32/end + 68/push 0/imm32/start + 89/<- %ecx 4/r32/esp + # var v/ebx: (handle var) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %ebx 4/r32/esp + # read function name + (next-mu-token *(ebp+8) %ecx) + # error checking + # if (word-slice == '{') abort + (slice-equal? %ecx "{") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32 + # if (word-slice == '->') abort + (slice-equal? %ecx "->") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32 + # if (word-slice == '}') abort + (slice-equal? %ecx "}") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32 + # if word-slice already defined, abort + (function-exists? %ecx) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-signature:error-duplicate/disp32 + # + (slice-starts-with? %ecx "break") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-signature:error-break/disp32 + (slice-starts-with? %ecx "loop") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-signature:error-loop/disp32 + # save function name + (slice-to-string Heap %ecx %edi) # Function-name + # save function inouts + { +$populate-mu-function-signature:check-for-inout: + (next-mu-token *(ebp+8) %ecx) + (slice-empty? %ecx) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= break/disp32 + # if (word-slice == '->') break + (slice-equal? %ecx "->") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= break/disp32 + # if (word-slice == '{') abort + (slice-equal? %ecx "{") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32 + # if (word-slice == '}') abort + (slice-equal? %ecx "}") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32 + # v = parse-var-with-type(word-slice, first-line) + (lookup *edi *(edi+4)) # Function-name Function-name => eax + (parse-var-with-type %ecx *(ebp+8) %ebx %eax *(ebp+0x10) *(ebp+0x14)) + # if (v->register != null) abort + # . eax: (addr var) = lookup(v) + (lookup *ebx *(ebx+4)) # => eax + 81 7/subop/compare *(eax+0x18) 0/imm32 # Var-register + 0f 85/jump-if-!= $populate-mu-function-signature:error2/disp32 + # if function name is not "main" + # and v->type contains an 'addr' anywhere except the start, abort + { + (lookup *edi *(edi+4)) # Function-name Function-name => eax + (string-equal? %eax "main") # => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 + (lookup *ebx *(ebx+4)) # => eax + (addr-payload-contains-addr? %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-signature:error-nested-addr-inout/disp32 + } + # assert(v->register == null) + # . eax: (addr var) = lookup(v) + (lookup *ebx *(ebx+4)) # => eax + 81 7/subop/compare *(eax+0x18) 0/imm32 # Var-register + 0f 85/jump-if-!= $populate-mu-function-signature:error2/disp32 + # v->block-depth is implicitly 0 + # + # out->inouts = append(v, out->inouts) + 8d/copy-address *(edi+8) 0/r32/eax # Function-inouts + (append-list Heap *ebx *(ebx+4) *(edi+8) *(edi+0xc) %eax) # Function-inouts, Function-inouts + # + e9/jump loop/disp32 + } + # save function outputs + { +$populate-mu-function-signature:check-for-out: + (next-mu-token *(ebp+8) %ecx) + (slice-empty? %ecx) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= break/disp32 + # if (word-slice == '{') abort + (slice-equal? %ecx "{") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32 + # if (word-slice == '->') abort + (slice-equal? %ecx "->") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32 + # if (word-slice == '}') abort + (slice-equal? %ecx "}") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32 + # v = parse-var-with-type(word-slice, first-line) + (lookup *edi *(edi+4)) # Function-name Function-name => eax + (parse-var-with-type %ecx *(ebp+8) %ebx %eax *(ebp+0x10) *(ebp+0x14)) + # assert(var->register != null) + # . eax: (addr var) = lookup(v) + (lookup *ebx *(ebx+4)) # => eax + 81 7/subop/compare *(eax+0x18) 0/imm32 # Var-register + 0f 84/jump-if-= $populate-mu-function-signature:error3/disp32 + # if (var->name != "_") abort + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (string-equal? %eax "_") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $populate-mu-function-signature:error4/disp32 + # if function name is not "lookup" + # and v->type is an addr, abort + { + (lookup *edi *(edi+4)) # Function-name Function-name => eax + (string-equal? %eax "lookup") # => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 + (lookup *ebx *(ebx+4)) # => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + (is-mu-addr-type? %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-function-signature:error-addr-output/disp32 + } + # out->outputs = append(v, out->outputs) + 8d/copy-address *(edi+0x10) 0/r32/eax # Function-outputs + (append-list Heap *ebx *(ebx+4) *(edi+0x10) *(edi+0x14) %eax) # Function-outputs, Function-outputs + # + e9/jump loop/disp32 + } +$populate-mu-function-signature:done: + (check-no-tokens-left *(ebp+8)) +$populate-mu-function-signature:end: + # . reclaim locals + 81 0/subop/add %esp 0x10/imm32 + # . restore registers + 5f/pop-to-edi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$populate-mu-function-signature:error1: + # error("function signature not in form 'fn <name> {'") + (write-buffered *(ebp+0x10) "function signature not in form 'fn <name> [inouts] [-> outputs] {' -- '") + (flush *(ebp+0x10)) + (rewind-stream *(ebp+8)) + (write-stream-data *(ebp+0x10) *(ebp+8)) + (write-buffered *(ebp+0x10) "'\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$populate-mu-function-signature:error2: + # error("fn " fn ": function inout '" var "' cannot be in a register") + (write-buffered *(ebp+0x10) "fn ") + 50/push-eax + (lookup *edi *(edi+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + 58/pop-to-eax + (write-buffered *(ebp+0x10) ": function inout '") + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' cannot be in a register") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$populate-mu-function-signature:error3: + # error("fn " fn ": function output '" var "' must be in a register") + (write-buffered *(ebp+0x10) "fn ") + 50/push-eax + (lookup *edi *(edi+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + 58/pop-to-eax + (write-buffered *(ebp+0x10) ": function output '") + (lookup *ebx *(ebx+4)) # => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' must be in a register, in instruction '") + (rewind-stream *(ebp+8)) + (write-stream-data *(ebp+0x10) *(ebp+8)) + (write-buffered *(ebp+0x10) "'\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$populate-mu-function-signature:error4: + # error("fn " fn ": function outputs cannot be named; rename '" var "' in the header to '_'") + (write-buffered *(ebp+0x10) "fn ") + 50/push-eax + (lookup *edi *(edi+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + 58/pop-to-eax + (write-buffered *(ebp+0x10) ": function outputs cannot be named; rename '") + (lookup *ebx *(ebx+4)) # => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' in the header to '_'\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$populate-mu-function-signature:error-duplicate: + (write-buffered *(ebp+0x10) "fn ") + (write-slice-buffered *(ebp+0x10) %ecx) + (write-buffered *(ebp+0x10) " defined more than once\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$populate-mu-function-signature:error-break: + (write-buffered *(ebp+0x10) "Sorry, I've reserved all function names starting with 'break' for now. Please contact mu@akkartik.com.\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$populate-mu-function-signature:error-loop: + (write-buffered *(ebp+0x10) "Sorry, I've reserved all function names starting with 'loop' for now. Please contact mu@akkartik.com.\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$populate-mu-function-signature:error-addr-output: + # error("fn " fn ": output cannot have an addr type; that could allow unsafe addresses to escape the function") + (write-buffered *(ebp+0x10) "fn ") + 50/push-eax + (lookup *edi *(edi+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + 58/pop-to-eax + (write-buffered *(ebp+0x10) ": output cannot have an addr type; that could allow unsafe addresses to escape the function\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$populate-mu-function-signature:error-nested-addr-inout: + # 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") + (write-buffered *(ebp+0x10) "fn ") + (lookup *edi *(edi+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": inout '") + (lookup *ebx *(ebx+4)) # => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (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") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +addr-payload-contains-addr?: # v: (addr var) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # var t/eax: (addr type-tree) = v->type + 8b/-> *(ebp+8) 0/r32/eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + # if t->right contains addr, return true + (lookup *(eax+0xc) *(eax+0x10)) # Type-tree-right Type-tree-right => eax + (type-tree-contains? %eax 2) # addr => eax + # we don't have to look at t->left as long as it's guaranteed to be an atom +$addr-payload-contains-addr?:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +type-tree-contains?: # t: (addr type-tree), n: type-id -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # if t is null, return false + 8b/-> *(ebp+8) 0/r32/eax + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $type-tree-contains?:end/disp32 # eax changes type + # if t is an atom, return (t->value == n) + 81 7/subop/compare *eax 0/imm32/false + { + 74/jump-if-= break/disp8 + 8b/-> *(ebp+0xc) 1/r32/ecx + 39/compare *(eax+4) 1/r32/ecx # Type-tree-value + 0f 94/set-if-= %al + 81 4/subop/and %eax 0xff/imm32 + eb/jump $type-tree-contains?:end/disp8 + } + # if t->left contains n, return true + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + (type-tree-contains? %eax *(ebp+0xc)) # => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= $type-tree-contains?:end/disp8 + # otherwise return whether t->right contains n + 8b/-> *(ebp+8) 0/r32/eax + (lookup *(eax+0xc) *(eax+0x10)) # Type-tree-right Type-tree-right => eax + (type-tree-contains? %eax *(ebp+0xc)) # => eax +$type-tree-contains?:end: + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +function-exists?: # s: (addr slice) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # var curr/ecx: (addr function) = functions + (lookup *_Program-functions *_Program-functions->payload) # => eax + 89/<- %ecx 0/r32/eax + { + # if (curr == null) break + 81 7/subop/compare %ecx 0/imm32 + 74/jump-if-= break/disp8 + # if (curr->name == s) return true + { + (lookup *ecx *(ecx+4)) # Function-name Function-name => eax + (slice-equal? *(ebp+8) %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + b8/copy-to-eax 1/imm32/true + e9/jump $function-exists?:end/disp32 + } + # curr = curr->next + (lookup *(ecx+0x20) *(ecx+0x24)) # Function-next Function-next => eax + 89/<- %ecx 0/r32/eax + # + eb/jump loop/disp8 + } + # var curr/ecx: (addr function) = signatures + (lookup *_Program-signatures *_Program-signatures->payload) # => eax + 89/<- %ecx 0/r32/eax + { + # if (curr == null) break + 81 7/subop/compare %ecx 0/imm32 + 74/jump-if-= break/disp8 + # if (curr->name == s) return true + { + (lookup *ecx *(ecx+4)) # Function-name Function-name => eax + (slice-equal? *(ebp+8) %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + b8/copy-to-eax 1/imm32/true + eb/jump $function-exists?:end/disp8 + } + # curr = curr->next + (lookup *(ecx+0x20) *(ecx+0x24)) # Function-next Function-next => eax + 89/<- %ecx 0/r32/eax + # + eb/jump loop/disp8 + } + # return false + b8/copy-to-eax 0/imm32/false +$function-exists?:end: + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-function-header-with-arg: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + 8b/-> *Primitive-type-ids 0/r32/eax + 89/<- *Type-id 0/r32/eax # stream-write + c7 0/subop/copy *_Program-functions 0/imm32 + c7 0/subop/copy *_Program-functions->payload 0/imm32 + c7 0/subop/copy *_Program-types 0/imm32 + c7 0/subop/copy *_Program-types->payload 0/imm32 + c7 0/subop/copy *_Program-signatures 0/imm32 + c7 0/subop/copy *_Program-signatures->payload 0/imm32 + (clear-stream _test-input-stream) + (write _test-input-stream "foo n: int {\n") + # var result/ecx: function + 2b/subtract *Function-size 4/r32/esp + 89/<- %ecx 4/r32/esp + (zero-out %ecx *Function-size) + # var vars/ebx: (stack live-var 16) + 81 5/subop/subtract %esp 0xc0/imm32 + 68/push 0xc0/imm32/size + 68/push 0/imm32/top + 89/<- %ebx 4/r32/esp + # convert + (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0) + # check result->name + (lookup *ecx *(ecx+4)) # Function-name Function-name => eax + (check-strings-equal %eax "foo" "F - test-function-header-with-arg/name") + # var v/edx: (addr var) = result->inouts->value + (lookup *(ecx+8) *(ecx+0xc)) # Function-inouts Function-inouts => eax + (lookup *eax *(eax+4)) # List-value List-value => eax + 89/<- %edx 0/r32/eax + # check v->name + (lookup *edx *(edx+4)) # Var-name Var-name => eax + (check-strings-equal %eax "n" "F - test-function-header-with-arg/inout:0") + # check v->type + (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + (check-ints-equal *eax 1 "F - test-function-header-with-arg/inout:0/type:0") # Type-tree-is-atom + (check-ints-equal *(eax+4) 1 "F - test-function-header-with-arg/inout:0/type:1") # Type-tree-value + (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-arg/inout:0/type:2") # Type-tree-right + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-function-header-with-multiple-args: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + 8b/-> *Primitive-type-ids 0/r32/eax + 89/<- *Type-id 0/r32/eax # stream-write + c7 0/subop/copy *_Program-functions 0/imm32 + c7 0/subop/copy *_Program-functions->payload 0/imm32 + c7 0/subop/copy *_Program-types 0/imm32 + c7 0/subop/copy *_Program-types->payload 0/imm32 + c7 0/subop/copy *_Program-signatures 0/imm32 + c7 0/subop/copy *_Program-signatures->payload 0/imm32 + (clear-stream _test-input-stream) + (write _test-input-stream "foo a: int, b: int c: int {\n") + # result/ecx: function + 2b/subtract *Function-size 4/r32/esp + 89/<- %ecx 4/r32/esp + (zero-out %ecx *Function-size) + # var vars/ebx: (stack live-var 16) + 81 5/subop/subtract %esp 0xc0/imm32 + 68/push 0xc0/imm32/size + 68/push 0/imm32/top + 89/<- %ebx 4/r32/esp + # convert + (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0) + # check result->name + (lookup *ecx *(ecx+4)) # Function-name Function-name => eax + (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args/name") + # var inouts/edx: (addr list var) = lookup(result->inouts) + (lookup *(ecx+8) *(ecx+0xc)) # Function-inouts Function-inouts => eax + 89/<- %edx 0/r32/eax +$test-function-header-with-multiple-args:inout0: + # var v/ebx: (addr var) = lookup(inouts->value) + (lookup *edx *(edx+4)) # List-value List-value => eax + 89/<- %ebx 0/r32/eax + # check v->name + (lookup *ebx *(ebx+4)) # Var-name Var-name => eax + (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args/inout:0") # Var-name + # check v->type + (lookup *(ebx+8) *(ebx+0xc)) # Var-type Var-type => eax + (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:0/type:0") # Type-tree-is-atom + (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:0/type:1") # Type-tree-value + (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:0/type:2") # Type-tree-right +$test-function-header-with-multiple-args:inout1: + # inouts = lookup(inouts->next) + (lookup *(edx+8) *(edx+0xc)) # List-next List-next => eax + 89/<- %edx 0/r32/eax + # v = lookup(inouts->value) + (lookup *edx *(edx+4)) # List-value List-value => eax + 89/<- %ebx 0/r32/eax + # check v->name + (lookup *ebx *(ebx+4)) # Var-name Var-name => eax + (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args/inout:1") # Var-name + # check v->type + (lookup *(ebx+8) *(ebx+0xc)) # Var-type Var-type => eax + (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:1/type:0") # Type-tree-is-atom + (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:1/type:1") # Type-tree-value + (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:1/type:2") # Type-tree-right +$test-function-header-with-multiple-args:inout2: + # inouts = lookup(inouts->next) + (lookup *(edx+8) *(edx+0xc)) # List-next List-next => eax + 89/<- %edx 0/r32/eax + # v = lookup(inouts->value) + (lookup *edx *(edx+4)) # List-value List-value => eax + 89/<- %ebx 0/r32/eax + # check v->name + (lookup *ebx *(ebx+4)) # Var-name Var-name => eax + (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args/inout:2") # Var-name + # check v->type + (lookup *(ebx+8) *(ebx+0xc)) # Var-type Var-type => eax + (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:2/type:0") # Type-tree-is-atom + (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:2/type:1") # Type-tree-value + (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:2/type:2") # Type-tree-right + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-function-header-with-multiple-args-and-outputs: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + 8b/-> *Primitive-type-ids 0/r32/eax + 89/<- *Type-id 0/r32/eax # stream-write + c7 0/subop/copy *_Program-functions 0/imm32 + c7 0/subop/copy *_Program-functions->payload 0/imm32 + c7 0/subop/copy *_Program-types 0/imm32 + c7 0/subop/copy *_Program-types->payload 0/imm32 + c7 0/subop/copy *_Program-signatures 0/imm32 + c7 0/subop/copy *_Program-signatures->payload 0/imm32 + (clear-stream _test-input-stream) + (write _test-input-stream "foo a: int, b: int, c: int -> _/ecx: int _/edx: int {\n") + # result/ecx: function + 2b/subtract *Function-size 4/r32/esp + 89/<- %ecx 4/r32/esp + (zero-out %ecx *Function-size) + # var vars/ebx: (stack live-var 16) + 81 5/subop/subtract %esp 0xc0/imm32 + 68/push 0xc0/imm32/size + 68/push 0/imm32/top + 89/<- %ebx 4/r32/esp + # convert + (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0) + # check result->name + (lookup *ecx *(ecx+4)) # Function-name Function-name => eax + (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args-and-outputs/name") + # var inouts/edx: (addr list var) = lookup(result->inouts) + (lookup *(ecx+8) *(ecx+0xc)) # Function-inouts Function-inouts => eax + 89/<- %edx 0/r32/eax +$test-function-header-with-multiple-args-and-outputs:inout0: + # var v/ebx: (addr var) = lookup(inouts->value) + (lookup *edx *(edx+4)) # List-value List-value => eax + 89/<- %ebx 0/r32/eax + # check v->name + (lookup *ebx *(ebx+4)) # Var-name Var-name => eax + (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args-and-outputs/inout:0") + # check v->type + (lookup *(ebx+8) *(ebx+0xc)) # Var-type Var-type => eax + (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:0") # Type-tree-is-atom + (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1") # Type-tree-value + (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:2") # Type-tree-right +$test-function-header-with-multiple-args-and-outputs:inout1: + # inouts = lookup(inouts->next) + (lookup *(edx+8) *(edx+0xc)) # List-next List-next => eax + 89/<- %edx 0/r32/eax + # v = lookup(inouts->value) + (lookup *edx *(edx+4)) # List-value List-value => eax + 89/<- %ebx 0/r32/eax + # check v->name + (lookup *ebx *(ebx+4)) # Var-name Var-name => eax + (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args-and-outputs/inout:1") + # check v->type + (lookup *(ebx+8) *(ebx+0xc)) # Var-type Var-type => eax + (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:0") # Type-tree-is-atom + (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1") # Type-tree-value + (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:2") # Type-tree-right +$test-function-header-with-multiple-args-and-outputs:inout2: + # inouts = lookup(inouts->next) + (lookup *(edx+8) *(edx+0xc)) # List-next List-next => eax + 89/<- %edx 0/r32/eax + # v = lookup(inouts->value) + (lookup *edx *(edx+4)) # List-value List-value => eax + 89/<- %ebx 0/r32/eax + # check v->name + (lookup *ebx *(ebx+4)) # Var-name Var-name => eax + (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args-and-outputs/inout:2") + # check v->type + (lookup *(ebx+8) *(ebx+0xc)) # Var-type Var-type => eax + (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:0") # Type-tree-is-atom + (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1") # Type-tree-value + (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:2") # Type-tree-right +$test-function-header-with-multiple-args-and-outputs:out0: + # var outputs/edx: (addr list var) = lookup(result->outputs) + (lookup *(ecx+0x10) *(ecx+0x14)) # Function-outputs Function-outputs => eax + 89/<- %edx 0/r32/eax + # v = lookup(outputs->value) + (lookup *edx *(edx+4)) # List-value List-value => eax + 89/<- %ebx 0/r32/eax + # check v->name + (lookup *ebx *(ebx+4)) # Var-name Var-name => eax + (check-strings-equal %eax "_" "F - test-function-header-with-multiple-args-and-outputs/output:0") + # check v->register + (lookup *(ebx+0x18) *(ebx+0x1c)) # Var-register Var-register => eax + (check-strings-equal %eax "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register") + # check v->type + (lookup *(ebx+8) *(ebx+0xc)) # Var-type Var-type => eax + (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:0") # Type-tree-is-atom + (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1") # Type-tree-value + (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:2") # Type-tree-right +$test-function-header-with-multiple-args-and-outputs:out1: + # outputs = lookup(outputs->next) + (lookup *(edx+8) *(edx+0xc)) # List-next List-next => eax + 89/<- %edx 0/r32/eax + # v = lookup(inouts->value) + (lookup *edx *(edx+4)) # List-value List-value => eax + 89/<- %ebx 0/r32/eax + # check v->name + (lookup *ebx *(ebx+4)) # Var-name Var-name => eax + (check-strings-equal %eax "_" "F - test-function-header-with-multiple-args-and-outputs/output:1") + # check v->register + (lookup *(ebx+0x18) *(ebx+0x1c)) # Var-register Var-register => eax + (check-strings-equal %eax "edx" "F - test-function-header-with-multiple-args-and-outputs/output:1/register") + # check v->type + (lookup *(ebx+8) *(ebx+0xc)) # Var-type Var-type => eax + (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:0") # Type-tree-is-atom + (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1") # Type-tree-value + (check-ints-equal *(eax+0c) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:2") # Type-tree-right + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# format for variables with types +# x: int +# x: int, +# x/eax: int +# x/eax: int, +# ignores at most one trailing comma +# does not support other, non-register metadata +# WARNING: modifies name +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) + # pseudocode: + # var s: slice + # if (!slice-ends-with(name, ":")) + # abort + # --name->end to skip ':' + # next-token-from-slice(name->start, name->end, '/', s) + # new-var-from-slice(s, out) + # ## register + # next-token-from-slice(s->end, name->end, '/', s) + # if (!slice-empty?(s)) + # out->register = slice-to-string(s) + # ## type + # var type: (handle type-tree) = parse-type(first-line) + # out->type = type + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + 57/push-edi + # esi = name + 8b/-> *(ebp+8) 6/r32/esi + # if (!slice-ends-with?(name, ":")) abort + 8b/-> *(esi+4) 1/r32/ecx # Slice-end + 49/decrement-ecx + 8a/copy-byte *ecx 1/r32/CL + 81 4/subop/and %ecx 0xff/imm32 + 81 7/subop/compare %ecx 0x3a/imm32/colon + 0f 85/jump-if-!= $parse-var-with-type:abort/disp32 + # --name->end to skip ':' + ff 1/subop/decrement *(esi+4) + # var s/ecx: slice + 68/push 0/imm32/end + 68/push 0/imm32/start + 89/<- %ecx 4/r32/esp +$parse-var-with-type:parse-name: + (next-token-from-slice *esi *(esi+4) 0x2f %ecx) # Slice-start, Slice-end, '/' +$parse-var-with-type:create-var: + # new-var-from-slice(s, out) + (new-var-from-slice Heap %ecx *(ebp+0x10)) + # save out->register +$parse-var-with-type:save-register: + # . var out-addr/edi: (addr var) = lookup(*out) + 8b/-> *(ebp+0x10) 7/r32/edi + (lookup *edi *(edi+4)) # => eax + 89/<- %edi 0/r32/eax + # . s = next-token(...) + (next-token-from-slice *(ecx+4) *(esi+4) 0x2f %ecx) # s->end, name->end, '/' + # . if (!slice-empty?(s)) out->register = slice-to-string(s) + { +$parse-var-with-type:write-register: + (slice-empty? %ecx) # => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 + # out->register = slice-to-string(s) + 8d/copy-address *(edi+0x18) 0/r32/eax # Var-register + (slice-to-string Heap %ecx %eax) + } +$parse-var-with-type:save-type: + 8d/copy-address *(edi+8) 0/r32/eax # Var-type + (parse-type Heap *(ebp+0xc) %eax *(ebp+0x18) *(ebp+0x1c)) +$parse-var-with-type:check-register: + (lookup *(edi+0x18) *(edi+0x1c)) # Var-register Var-register => eax + 3d/compare-eax-and 0/imm32 + 74/jump-if-= $parse-var-with-type:end/disp8 + (is-float-register? %eax) # => eax + { + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + # var is in a float register; ensure type is float + (lookup *(edi+8) *(edi+0xc)) # Var-type Var-type => eax + (is-simple-mu-type? %eax 0xf) # float => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $parse-var-with-type:error-non-float-in-floating-point-register/disp32 + eb/jump $parse-var-with-type:end/disp8 + } + # var is not in a float register; ensure type is not float + (lookup *(edi+8) *(edi+0xc)) # Var-type Var-type => eax + (is-simple-mu-type? %eax 0xf) # float => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $parse-var-with-type:error-float-in-integer-register/disp32 +$parse-var-with-type:end: + # . reclaim locals + 81 0/subop/add %esp 8/imm32 + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$parse-var-with-type:abort: + # error("fn " fn ": var should have form 'name: type' in '" line "'\n") + (write-buffered *(ebp+0x18) "fn ") + (write-buffered *(ebp+0x18) *(ebp+0x14)) + (write-buffered *(ebp+0x18) ": var should have form 'name: type' in '") + (flush *(ebp+0x18)) + (rewind-stream *(ebp+0xc)) + (write-stream-data *(ebp+0x18) *(ebp+0xc)) + (write-buffered *(ebp+0x18) "'\n") + (flush *(ebp+0x18)) + (stop *(ebp+0x1c) 1) + # never gets here + +$parse-var-with-type:error-float-in-integer-register: + # error("fn " fn ": float var '" var "' should be in a floating-point register\n") + (write-buffered *(ebp+0x18) "fn ") + (write-buffered *(ebp+0x18) *(ebp+0x14)) + (write-buffered *(ebp+0x18) ": float var '") + (lookup *edi *(edi+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x18) %eax) + (write-buffered *(ebp+0x18) "' should be in a floating-point register\n") + (flush *(ebp+0x18)) + (stop *(ebp+0x1c) 1) + # never gets here + +$parse-var-with-type:error-non-float-in-floating-point-register: + # error("fn " fn ": non-float var '" var "' should be in an integer register\n") + (write-buffered *(ebp+0x18) "fn ") + (write-buffered *(ebp+0x18) *(ebp+0x14)) + (write-buffered *(ebp+0x18) ": non-float var '") + (lookup *edi *(edi+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x18) %eax) + (write-buffered *(ebp+0x18) "' should be in an integer register\n") + (flush *(ebp+0x18)) + (stop *(ebp+0x1c) 1) + # never gets here + +is-float-register?: # r: (addr array byte) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # + (get Mu-registers-unique *(ebp+8) 0xc "Mu-registers-unique") # => eax + 81 7/subop/compare *eax 8/imm32/start-of-floating-point-registers + 0f 9d/set-if->= %al + 81 4/subop/and %eax 0xff/imm32 +$is-float-register?:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +parse-type: # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle type-tree), err: (addr buffered-file), ed: (addr exit-descriptor) + # pseudocode: + # var s: slice = next-mu-token(in) + # assert s != "" + # assert s != "->" + # assert s != "{" + # assert s != "}" + # if s == ")" + # return + # out = allocate(Type-tree) + # if s != "(" + # HACK: if s is an int, parse and return it + # out->is-atom? = true + # if (s[0] == "_") + # out->value = type-parameter + # out->parameter-name = slice-to-string(ad, s) + # else + # out->value = pos-or-insert-slice(Type-id, s) + # return + # out->left = parse-type(ad, in) + # out->right = parse-type-tree(ad, in) + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + # clear out + (zero-out *(ebp+0x10) *Handle-size) + # var s/ecx: slice + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %ecx 4/r32/esp + # s = next-mu-token(in) + (next-mu-token *(ebp+0xc) %ecx) +#? (write-buffered Stderr "tok: ") +#? (write-slice-buffered Stderr %ecx) +#? (write-buffered Stderr "$\n") +#? (flush Stderr) + # assert s != "" + (slice-equal? %ecx "") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $parse-type:abort/disp32 + # assert s != "{" + (slice-equal? %ecx "{") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $parse-type:abort/disp32 + # assert s != "}" + (slice-equal? %ecx "}") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $parse-type:abort/disp32 + # assert s != "->" + (slice-equal? %ecx "->") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $parse-type:abort/disp32 + # if (s == ")") return + (slice-equal? %ecx ")") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $parse-type:end/disp32 + # out = new tree + (allocate *(ebp+8) *Type-tree-size *(ebp+0x10)) + # var out-addr/edx: (addr type-tree) = lookup(*out) + 8b/-> *(ebp+0x10) 2/r32/edx + (lookup *edx *(edx+4)) # => eax + 89/<- %edx 0/r32/eax + { + # if (s != "(") break + (slice-equal? %ecx "(") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= break/disp32 + # if s is a number, store it in the type's size field + { +$parse-type:check-for-int: + # var tmp/eax: byte = *s->slice + 8b/-> *ecx 0/r32/eax + 8a/copy-byte *eax 0/r32/AL + 81 4/subop/and %eax 0xff/imm32 + # TODO: raise an error on `var x: (array int a)` + (is-decimal-digit? %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 +$parse-type:int: + # strip out metadata + (next-token-from-slice *ecx *(ecx+4) 0x2f %ecx) + # + (check-mu-hex-int %ecx *(ebp+0x14) *(ebp+0x18)) + (parse-hex-int-from-slice %ecx) # => eax + c7 0/subop/copy *(edx+4) 9/imm32/type-id-array-capacity # Type-tree-value + 89/<- *(edx+8) 0/r32/eax # Type-tree-value-size + e9/jump $parse-type:end/disp32 + } +$parse-type:atom: + # out->is-atom? = true + c7 0/subop/copy *edx 1/imm32/true # Type-tree-is-atom + { +$parse-type:check-for-type-parameter: + # var tmp/eax: byte = *s->slice + 8b/-> *ecx 0/r32/eax + 8a/copy-byte *eax 0/r32/AL + 81 4/subop/and %eax 0xff/imm32 + # if (tmp != '_') break + 3d/compare-eax-and 0x5f/imm32/_ + 75/jump-if-!= break/disp8 +$parse-type:type-parameter: + # out->value = type-parameter + c7 0/subop/copy *(edx+4) 0xa/imm32/type-parameter # Type-tree-value + # out->parameter-name = slice-to-string(ad, s) + 8d/copy-address *(edx+8) 0/r32/eax # Type-tree-parameter-name + (slice-to-string *(ebp+8) %ecx %eax) + e9/jump $parse-type:end/disp32 + } +$parse-type:non-type-parameter: + # out->value = pos-or-insert-slice(Type-id, s) + (pos-or-insert-slice Type-id %ecx) # => eax + 89/<- *(edx+4) 0/r32/eax # Type-tree-value + e9/jump $parse-type:end/disp32 + } +$parse-type:non-atom: + # otherwise s == "(" + # out->left = parse-type(ad, in) + 8d/copy-address *(edx+4) 0/r32/eax # Type-tree-left + (parse-type *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18)) + # out->right = parse-type-tree(ad, in) + 8d/copy-address *(edx+0xc) 0/r32/eax # Type-tree-right + (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18)) +$parse-type:end: + # . reclaim locals + 81 0/subop/add %esp 8/imm32 + # . restore registers + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$parse-type:abort: + # error("unexpected token when parsing type: '" s "'\n") + (write-buffered *(ebp+0x14) "unexpected token when parsing type: '") + (write-slice-buffered *(ebp+0x14) %ecx) + (write-buffered *(ebp+0x14) "'\n") + (flush *(ebp+0x14)) + (stop *(ebp+0x18) 1) + # never gets here + +parse-type-tree: # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle type-tree), err: (addr buffered-file), ed: (addr exit-descriptor) + # pseudocode: + # var tmp: (handle type-tree) = parse-type(ad, in) + # if tmp == 0 + # return 0 + # out = allocate(Type-tree) + # out->left = tmp + # out->right = parse-type-tree(ad, in) + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + # + (zero-out *(ebp+0x10) *Handle-size) + # var tmp/ecx: (handle type-tree) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %ecx 4/r32/esp + # tmp = parse-type(ad, in) + (parse-type *(ebp+8) *(ebp+0xc) %ecx *(ebp+0x14) *(ebp+0x18)) + # if (tmp == 0) return + 81 7/subop/compare *ecx 0/imm32 + 74/jump-if-= $parse-type-tree:end/disp8 + # out = new tree + (allocate *(ebp+8) *Type-tree-size *(ebp+0x10)) + # var out-addr/edx: (addr tree) = lookup(*out) + 8b/-> *(ebp+0x10) 2/r32/edx + (lookup *edx *(edx+4)) # => eax + 89/<- %edx 0/r32/eax + # out->left = tmp + 8b/-> *ecx 0/r32/eax + 89/<- *(edx+4) 0/r32/eax # Type-tree-left + 8b/-> *(ecx+4) 0/r32/eax + 89/<- *(edx+8) 0/r32/eax # Type-tree-left + # out->right = parse-type-tree(ad, in) + 8d/copy-address *(edx+0xc) 0/r32/eax # Type-tree-right + (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18)) +$parse-type-tree:end: + # . reclaim locals + 81 0/subop/add %esp 8/imm32 + # . restore registers + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +next-mu-token: # in: (addr stream byte), out: (addr slice) + # pseudocode: + # start: + # skip-chars-matching-whitespace(in) + # if in->read >= in->write # end of in + # out = {0, 0} + # return + # out->start = &in->data[in->read] + # var curr-byte/eax: byte = in->data[in->read] + # if curr->byte == ',' # comment token + # ++in->read + # goto start + # if curr-byte == '#' # comment + # goto done # treat as eof + # if curr-byte == '"' # string literal + # skip-string(in) + # goto done # no metadata + # if curr-byte == '(' + # ++in->read + # goto done + # if curr-byte == ')' + # ++in->read + # goto done + # # read a word + # while true + # if in->read >= in->write + # break + # curr-byte = in->data[in->read] + # if curr-byte == ' ' + # break + # if curr-byte == '\r' + # break + # if curr-byte == '\n' + # break + # if curr-byte == '(' + # break + # if curr-byte == ')' + # break + # if curr-byte == ',' + # break + # ++in->read + # done: + # out->end = &in->data[in->read] + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 56/push-esi + 57/push-edi + # esi = in + 8b/-> *(ebp+8) 6/r32/esi + # edi = out + 8b/-> *(ebp+0xc) 7/r32/edi +$next-mu-token:start: + (skip-chars-matching-whitespace %esi) +$next-mu-token:check0: + # if (in->read >= in->write) return out = {0, 0} + # . ecx = in->read + 8b/-> *(esi+4) 1/r32/ecx + # . if (ecx >= in->write) return out = {0, 0} + 3b/compare<- *esi 1/r32/ecx + c7 0/subop/copy *edi 0/imm32 + c7 0/subop/copy *(edi+4) 0/imm32 + 0f 8d/jump-if->= $next-mu-token:end/disp32 + # out->start = &in->data[in->read] + 8d/copy-address *(esi+ecx+0xc) 0/r32/eax + 89/<- *edi 0/r32/eax + # var curr-byte/eax: byte = in->data[in->read] + 31/xor-with %eax 0/r32/eax + 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL + { +$next-mu-token:check-for-comma: + # if (curr-byte != ',') break + 3d/compare-eax-and 0x2c/imm32/comma + 75/jump-if-!= break/disp8 + # ++in->read + ff 0/subop/increment *(esi+4) + # restart + e9/jump $next-mu-token:start/disp32 + } + { +$next-mu-token:check-for-comment: + # if (curr-byte != '#') break + 3d/compare-eax-and 0x23/imm32/pound + 75/jump-if-!= break/disp8 + # return eof + e9/jump $next-mu-token:done/disp32 + } + { +$next-mu-token:check-for-string-literal: + # if (curr-byte != '"') break + 3d/compare-eax-and 0x22/imm32/dquote + 75/jump-if-!= break/disp8 + (skip-string %esi) + # return + e9/jump $next-mu-token:done/disp32 + } + { +$next-mu-token:check-for-open-paren: + # if (curr-byte != '(') break + 3d/compare-eax-and 0x28/imm32/open-paren + 75/jump-if-!= break/disp8 + # ++in->read + ff 0/subop/increment *(esi+4) + # return + e9/jump $next-mu-token:done/disp32 + } + { +$next-mu-token:check-for-close-paren: + # if (curr-byte != ')') break + 3d/compare-eax-and 0x29/imm32/close-paren + 75/jump-if-!= break/disp8 + # ++in->read + ff 0/subop/increment *(esi+4) + # return + e9/jump $next-mu-token:done/disp32 + } + { +$next-mu-token:regular-word-without-metadata: + # if (in->read >= in->write) break + # . ecx = in->read + 8b/-> *(esi+4) 1/r32/ecx + # . if (ecx >= in->write) break + 3b/compare<- *esi 1/r32/ecx + 7d/jump-if->= break/disp8 + # var c/eax: byte = in->data[in->read] + 31/xor-with %eax 0/r32/eax + 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL + # if (c == ' ') break + 3d/compare-eax-and 0x20/imm32/space + 74/jump-if-= break/disp8 + # if (c == '\r') break + 3d/compare-eax-and 0xd/imm32/carriage-return + 74/jump-if-= break/disp8 + # if (c == '\n') break + 3d/compare-eax-and 0xa/imm32/newline + 74/jump-if-= break/disp8 + # if (c == '(') break + 3d/compare-eax-and 0x28/imm32/open-paren + 0f 84/jump-if-= break/disp32 + # if (c == ')') break + 3d/compare-eax-and 0x29/imm32/close-paren + 0f 84/jump-if-= break/disp32 + # if (c == ',') break + 3d/compare-eax-and 0x2c/imm32/comma + 0f 84/jump-if-= break/disp32 + # ++in->read + ff 0/subop/increment *(esi+4) + # + e9/jump loop/disp32 + } +$next-mu-token:done: + # out->end = &in->data[in->read] + 8b/-> *(esi+4) 1/r32/ecx + 8d/copy-address *(esi+ecx+0xc) 0/r32/eax + 89/<- *(edi+4) 0/r32/eax +$next-mu-token:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +pos-or-insert-slice: # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # if (pos-slice(arr, s) != -1) return it + (pos-slice *(ebp+8) *(ebp+0xc)) # => eax + 3d/compare-eax-and -1/imm32 + 75/jump-if-!= $pos-or-insert-slice:end/disp8 +$pos-or-insert-slice:insert: + # var s2/eax: (handle array byte) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %eax 4/r32/esp + (slice-to-string Heap *(ebp+0xc) %eax) + # throw away alloc-id + (lookup *eax *(eax+4)) # => eax + (write-int *(ebp+8) %eax) + (pos-slice *(ebp+8) *(ebp+0xc)) # => eax +$pos-or-insert-slice:end: + # . reclaim locals + 81 0/subop/add %esp 8/imm32 + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# return the index in an array of strings matching 's', -1 if not found +# index is denominated in elements, not bytes +pos-slice: # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi +#? (write-buffered Stderr "pos-slice: ") +#? (write-slice-buffered Stderr *(ebp+0xc)) +#? (write-buffered Stderr "\n") +#? (flush Stderr) + # esi = arr + 8b/-> *(ebp+8) 6/r32/esi + # var index/ecx: int = 0 + b9/copy-to-ecx 0/imm32 + # var curr/edx: (addr (addr array byte)) = arr->data + 8d/copy-address *(esi+0xc) 2/r32/edx + # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write] + 8b/-> *esi 3/r32/ebx + 8d/copy-address *(esi+ebx+0xc) 3/r32/ebx + { +#? (write-buffered Stderr " ") +#? (write-int32-hex-buffered Stderr %ecx) +#? (write-buffered Stderr "\n") +#? (flush Stderr) + # if (curr >= max) return -1 + 39/compare %edx 3/r32/ebx + b8/copy-to-eax -1/imm32 + 73/jump-if-addr>= $pos-slice:end/disp8 + # if (slice-equal?(s, *curr)) break + (slice-equal? *(ebp+0xc) *edx) # => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 + # ++index + 41/increment-ecx + # curr += 4 + 81 0/subop/add %edx 4/imm32 + # + eb/jump loop/disp8 + } + # return index + 89/<- %eax 1/r32/ecx +$pos-slice:end: +#? (write-buffered Stderr "=> ") +#? (write-int32-hex-buffered Stderr %eax) +#? (write-buffered Stderr "\n") + # . restore registers + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-parse-var-with-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + 8b/-> *Primitive-type-ids 0/r32/eax + 89/<- *Type-id 0/r32/eax # stream-write + # (eax..ecx) = "x:" + b8/copy-to-eax "x:"/imm32 + 8b/-> *eax 1/r32/ecx + 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 05/add-to-eax 4/imm32 + # var slice/ecx: slice = {eax, ecx} + 51/push-ecx + 50/push-eax + 89/<- %ecx 4/r32/esp + # _test-input-stream contains "int" + (clear-stream _test-input-stream) + (write _test-input-stream "int") + # var v/edx: (handle var) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + # + (parse-var-with-type %ecx _test-input-stream %edx 0 Stderr 0) + # var v-addr/edx: (addr var) = lookup(v) + (lookup *edx *(edx+4)) # => eax + 89/<- %edx 0/r32/eax + # check v-addr->name + (lookup *edx *(edx+4)) # Var-name Var-name => eax + (check-strings-equal %eax "x" "F - test-parse-var-with-type/name") + # check v-addr->type + (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + (check-ints-equal *eax 1 "F - test-parse-var-with-type/type:0") # Type-tree-is-atom + (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type/type:1") # Type-tree-value + (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type/type:2") # Type-tree-right + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-parse-var-with-type-and-register: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + 8b/-> *Primitive-type-ids 0/r32/eax + 89/<- *Type-id 0/r32/eax # stream-write + # (eax..ecx) = "x/eax:" + b8/copy-to-eax "x/eax:"/imm32 + 8b/-> *eax 1/r32/ecx + 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 05/add-to-eax 4/imm32 + # var slice/ecx: slice = {eax, ecx} + 51/push-ecx + 50/push-eax + 89/<- %ecx 4/r32/esp + # _test-input-stream contains "int" + (clear-stream _test-input-stream) + (write _test-input-stream "int") + # var v/edx: (handle var) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + # + (parse-var-with-type %ecx _test-input-stream %edx 0 Stderr 0) + # var v-addr/edx: (addr var) = lookup(v) + (lookup *edx *(edx+4)) # => eax + 89/<- %edx 0/r32/eax + # check v-addr->name + (lookup *edx *(edx+4)) # Var-name Var-name => eax + (check-strings-equal %eax "x" "F - test-parse-var-with-type-and-register/name") + # check v-addr->register + (lookup *(edx+0x18) *(edx+0x1c)) # Var-register Var-register => eax + (check-strings-equal %eax "eax" "F - test-parse-var-with-type-and-register/register") + # check v-addr->type + (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + (check-ints-equal *eax 1 "F - test-parse-var-with-type-and-register/type:0") # Type-tree-is-atom + (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type-and-register/type:1") # Type-tree-left + (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type-and-register/type:2") # Type-tree-right + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-parse-var-with-trailing-characters: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + 8b/-> *Primitive-type-ids 0/r32/eax + 89/<- *Type-id 0/r32/eax # stream-write + # (eax..ecx) = "x:" + b8/copy-to-eax "x:"/imm32 + 8b/-> *eax 1/r32/ecx + 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 05/add-to-eax 4/imm32 + # var slice/ecx: slice = {eax, ecx} + 51/push-ecx + 50/push-eax + 89/<- %ecx 4/r32/esp + # _test-input-stream contains "int," + (clear-stream _test-input-stream) + (write _test-input-stream "int,") + # var v/edx: (handle var) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + # + (parse-var-with-type %ecx _test-input-stream %edx 0 Stderr 0) + # var v-addr/edx: (addr var) = lookup(v) + (lookup *edx *(edx+4)) # => eax + 89/<- %edx 0/r32/eax + # check v-addr->name + (lookup *edx *(edx+4)) # Var-name Var-name => eax + (check-strings-equal %eax "x" "F - test-parse-var-with-trailing-characters/name") + # check v-addr->register + (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-trailing-characters/register") # Var-register + # check v-addr->type + (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + (check-ints-equal *eax 1 "F - test-parse-var-with-trailing-characters/type:0") # Type-tree-is-atom + (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-trailing-characters/type:1") # Type-tree-left + (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-trailing-characters/type:1") # Type-tree-right + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-parse-var-with-register-and-trailing-characters: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + 8b/-> *Primitive-type-ids 0/r32/eax + 89/<- *Type-id 0/r32/eax # stream-write + # (eax..ecx) = "x/eax:" + b8/copy-to-eax "x/eax:"/imm32 + 8b/-> *eax 1/r32/ecx + 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 05/add-to-eax 4/imm32 + # var slice/ecx: slice = {eax, ecx} + 51/push-ecx + 50/push-eax + 89/<- %ecx 4/r32/esp + # _test-input-stream contains "int," + (clear-stream _test-input-stream) + (write _test-input-stream "int,") + # var v/edx: (handle var) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + # + (parse-var-with-type %ecx _test-input-stream %edx 0 Stderr 0) + # var v-addr/edx: (addr var) = lookup(v) + (lookup *edx *(edx+4)) # => eax + 89/<- %edx 0/r32/eax + # check v-addr->name + (lookup *edx *(edx+4)) # Var-name Var-name => eax + (check-strings-equal %eax "x" "F - test-parse-var-with-register-and-trailing-characters/name") + # check v-addr->register + (lookup *(edx+0x18) *(edx+0x1c)) # Var-register Var-register => eax + (check-strings-equal %eax "eax" "F - test-parse-var-with-register-and-trailing-characters/register") + # check v-addr->type + (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + (check-ints-equal *eax 1 "F - test-parse-var-with-register-and-trailing-characters/type:0") # Type-tree-is-atom + (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-register-and-trailing-characters/type:1") # Type-tree-left + (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-register-and-trailing-characters/type:2") # Type-tree-right + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-parse-var-with-compound-type: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + 8b/-> *Primitive-type-ids 0/r32/eax + 89/<- *Type-id 0/r32/eax # stream-write + # (eax..ecx) = "x:" + b8/copy-to-eax "x:"/imm32 + 8b/-> *eax 1/r32/ecx + 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 05/add-to-eax 4/imm32 + # var slice/ecx: slice = {eax, ecx} + 51/push-ecx + 50/push-eax + 89/<- %ecx 4/r32/esp + # _test-input-stream contains "(addr int)" + (clear-stream _test-input-stream) + (write _test-input-stream "(addr int)") + # var v/edx: (handle var) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + # + (parse-var-with-type %ecx _test-input-stream %edx 0 Stderr 0) + # var v-addr/edx: (addr var) = lookup(v) + (lookup *edx *(edx+4)) # => eax + 89/<- %edx 0/r32/eax + # check v-addr->name + (lookup *edx *(edx+4)) # Var-name Var-name => eax + (check-strings-equal %eax "x" "F - test-parse-var-with-compound-type/name") + # check v-addr->register + (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-compound-type/register") # Var-register + # - check v-addr->type + # var type/edx: (addr type-tree) = var->type + (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + 89/<- %edx 0/r32/eax + # type is a non-atom + (check-ints-equal *edx 0 "F - test-parse-var-with-compound-type/type:0") # Type-tree-is-atom + # type->left == atom(addr) + (lookup *(edx+4) *(edx+8)) # Type-tree-left Type-tree-left => eax + (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:1") # Type-tree-is-atom + (check-ints-equal *(eax+4) 2 "F - test-parse-var-with-compound-type/type:2") # Type-tree-value + # type->right->left == atom(int) + (lookup *(edx+0xc) *(edx+0x10)) # Type-tree-right Type-tree-right => eax + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:3") # Type-tree-is-atom + (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-compound-type/type:4") # Type-tree-value + # type->right->right == null + (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-compound-type/type:5") # Type-tree-right + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# identifier starts with a letter or '$' or '_' +# no constraints at the moment on later letters +# all we really want to do so far is exclude '{', '}' and '->' +is-identifier?: # in: (addr slice) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # if (slice-empty?(in)) return false + (slice-empty? *(ebp+8)) # => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= $is-identifier?:false/disp8 + # var c/eax: byte = *in->start + 8b/-> *(ebp+8) 0/r32/eax + 8b/-> *eax 0/r32/eax + 8a/copy-byte *eax 0/r32/AL + 81 4/subop/and %eax 0xff/imm32 + # if (c == '$') return true + 3d/compare-eax-and 0x24/imm32/$ + 74/jump-if-= $is-identifier?:true/disp8 + # if (c == '_') return true + 3d/compare-eax-and 0x5f/imm32/_ + 74/jump-if-= $is-identifier?:true/disp8 + # drop case + 25/and-eax-with 0x5f/imm32 + # if (c < 'A') return false + 3d/compare-eax-and 0x41/imm32/A + 7c/jump-if-< $is-identifier?:false/disp8 + # if (c > 'Z') return false + 3d/compare-eax-and 0x5a/imm32/Z + 7f/jump-if-> $is-identifier?:false/disp8 + # otherwise return true +$is-identifier?:true: + b8/copy-to-eax 1/imm32/true + eb/jump $is-identifier?:end/disp8 +$is-identifier?:false: + b8/copy-to-eax 0/imm32/false +$is-identifier?:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-is-identifier-dollar: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # (eax..ecx) = "$a" + b8/copy-to-eax "$a"/imm32 + 8b/-> *eax 1/r32/ecx + 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 05/add-to-eax 4/imm32 + # var slice/ecx: slice = {eax, ecx} + 51/push-ecx + 50/push-eax + 89/<- %ecx 4/r32/esp + # + (is-identifier? %ecx) + (check-ints-equal %eax 1 "F - test-is-identifier-dollar") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-is-identifier-underscore: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # (eax..ecx) = "_a" + b8/copy-to-eax "_a"/imm32 + 8b/-> *eax 1/r32/ecx + 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 05/add-to-eax 4/imm32 + # var slice/ecx: slice = {eax, ecx} + 51/push-ecx + 50/push-eax + 89/<- %ecx 4/r32/esp + # + (is-identifier? %ecx) + (check-ints-equal %eax 1 "F - test-is-identifier-underscore") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-is-identifier-a: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # (eax..ecx) = "a$" + b8/copy-to-eax "a$"/imm32 + 8b/-> *eax 1/r32/ecx + 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 05/add-to-eax 4/imm32 + # var slice/ecx: slice = {eax, ecx} + 51/push-ecx + 50/push-eax + 89/<- %ecx 4/r32/esp + # + (is-identifier? %ecx) + (check-ints-equal %eax 1 "F - test-is-identifier-a") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-is-identifier-z: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # (eax..ecx) = "z$" + b8/copy-to-eax "z$"/imm32 + 8b/-> *eax 1/r32/ecx + 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 05/add-to-eax 4/imm32 + # var slice/ecx: slice = {eax, ecx} + 51/push-ecx + 50/push-eax + 89/<- %ecx 4/r32/esp + # + (is-identifier? %ecx) + (check-ints-equal %eax 1 "F - test-is-identifier-z") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-is-identifier-A: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # (eax..ecx) = "A$" + b8/copy-to-eax "A$"/imm32 + 8b/-> *eax 1/r32/ecx + 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 05/add-to-eax 4/imm32 + # var slice/ecx: slice = {eax, ecx} + 51/push-ecx + 50/push-eax + 89/<- %ecx 4/r32/esp + # + (is-identifier? %ecx) + (check-ints-equal %eax 1 "F - test-is-identifier-A") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-is-identifier-Z: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # (eax..ecx) = "Z$" + b8/copy-to-eax "Z$"/imm32 + 8b/-> *eax 1/r32/ecx + 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 05/add-to-eax 4/imm32 + # var slice/ecx: slice = {eax, ecx} + 51/push-ecx + 50/push-eax + 89/<- %ecx 4/r32/esp + # + (is-identifier? %ecx) + (check-ints-equal %eax 1 "F - test-is-identifier-Z") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-is-identifier-at: + # character before 'A' is invalid + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # (eax..ecx) = "@a" + b8/copy-to-eax "@a"/imm32 + 8b/-> *eax 1/r32/ecx + 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 05/add-to-eax 4/imm32 + # var slice/ecx: slice = {eax, ecx} + 51/push-ecx + 50/push-eax + 89/<- %ecx 4/r32/esp + # + (is-identifier? %ecx) + (check-ints-equal %eax 0 "F - test-is-identifier-@") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-is-identifier-square-bracket: + # character after 'Z' is invalid + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # (eax..ecx) = "[a" + b8/copy-to-eax "[a"/imm32 + 8b/-> *eax 1/r32/ecx + 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 05/add-to-eax 4/imm32 + # var slice/ecx: slice = {eax, ecx} + 51/push-ecx + 50/push-eax + 89/<- %ecx 4/r32/esp + # + (is-identifier? %ecx) + (check-ints-equal %eax 0 "F - test-is-identifier-@") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-is-identifier-backtick: + # character before 'a' is invalid + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # (eax..ecx) = "`a" + b8/copy-to-eax "`a"/imm32 + 8b/-> *eax 1/r32/ecx + 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 05/add-to-eax 4/imm32 + # var slice/ecx: slice = {eax, ecx} + 51/push-ecx + 50/push-eax + 89/<- %ecx 4/r32/esp + # + (is-identifier? %ecx) + (check-ints-equal %eax 0 "F - test-is-identifier-backtick") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-is-identifier-curly-brace-open: + # character after 'z' is invalid; also used for blocks + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # (eax..ecx) = "{a" + b8/copy-to-eax "{a"/imm32 + 8b/-> *eax 1/r32/ecx + 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 05/add-to-eax 4/imm32 + # var slice/ecx: slice = {eax, ecx} + 51/push-ecx + 50/push-eax + 89/<- %ecx 4/r32/esp + # + (is-identifier? %ecx) + (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-is-identifier-curly-brace-close: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # (eax..ecx) = "}a" + b8/copy-to-eax "}a"/imm32 + 8b/-> *eax 1/r32/ecx + 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 05/add-to-eax 4/imm32 + # var slice/ecx: slice = {eax, ecx} + 51/push-ecx + 50/push-eax + 89/<- %ecx 4/r32/esp + # + (is-identifier? %ecx) + (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-is-identifier-hyphen: + # disallow leading '-' since '->' has special meaning + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # (eax..ecx) = "-a" + b8/copy-to-eax "-a"/imm32 + 8b/-> *eax 1/r32/ecx + 8d/copy-address *(eax+ecx+4) 1/r32/ecx + 05/add-to-eax 4/imm32 + # var slice/ecx: slice = {eax, ecx} + 51/push-ecx + 50/push-eax + 89/<- %ecx 4/r32/esp + # + (is-identifier? %ecx) + (check-ints-equal %eax 0 "F - test-is-identifier-hyphen") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +populate-mu-function-body: # in: (addr buffered-file), out: (addr function), vars: (addr stack live-var), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 56/push-esi + 57/push-edi + # esi = in + 8b/-> *(ebp+8) 6/r32/esi + # edi = out + 8b/-> *(ebp+0xc) 7/r32/edi + # initialize some global state + c7 0/subop/copy *Curr-block-depth 1/imm32 + # parse-mu-block(in, vars, out, out->body) + 8d/copy-address *(edi+0x18) 0/r32/eax # Function-body + (parse-mu-block %esi *(ebp+0x10) %edi %eax *(ebp+0x14) *(ebp+0x18)) +$populate-mu-function-body:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# parses a block, assuming that the leading '{' has already been read by the caller +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) + # pseudocode: + # var line: (stream byte 512) + # var word-slice: slice + # allocate(Heap, Stmt-size, out) + # var out-addr: (addr block) = lookup(*out) + # out-addr->tag = 0/block + # out-addr->var = some unique name + # push(vars, {out-addr->var, false}) + # while true # line loop + # clear-stream(line) + # read-line-buffered(in, line) + # if (line->write == 0) break # end of file + # word-slice = next-mu-token(line) + # if slice-empty?(word-slice) # end of line + # continue + # else if slice-starts-with?(word-slice, "#") + # continue + # else if slice-equal?(word-slice, "{") + # assert(no-tokens-in(line)) + # block = parse-mu-block(in, vars, fn) + # append-to-block(out-addr, block) + # else if slice-equal?(word-slice, "}") + # break + # else if slice-ends-with?(word-slice, ":") + # # TODO: error-check the rest of 'line' + # --word-slice->end to skip ':' + # named-block = parse-mu-named-block(word-slice, in, vars, fn) + # append-to-block(out-addr, named-block) + # else if slice-equal?(word-slice, "var") + # var-def = parse-mu-var-def(line, vars, fn) + # append-to-block(out-addr, var-def) + # else + # stmt = parse-mu-stmt(line, vars, fn) + # append-to-block(out-addr, stmt) + # pop(vars) + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 57/push-edi + # var line/ecx: (stream byte 512) + 81 5/subop/subtract %esp 0x200/imm32 + 68/push 0x200/imm32/size + 68/push 0/imm32/read + 68/push 0/imm32/write + 89/<- %ecx 4/r32/esp + # var word-slice/edx: slice + 68/push 0/imm32/end + 68/push 0/imm32/start + 89/<- %edx 4/r32/esp + # allocate into out + (allocate Heap *Stmt-size *(ebp+0x14)) + # var out-addr/edi: (addr block) = lookup(*out) + 8b/-> *(ebp+0x14) 7/r32/edi + (lookup *edi *(edi+4)) # => eax + 89/<- %edi 0/r32/eax + # out-addr->tag is 0 (block) by default + # set out-addr->var + 8d/copy-address *(edi+0xc) 0/r32/eax # Block-var + (new-block-name *(ebp+0x10) %eax) + # push(vars, out-addr->var) + (push *(ebp+0xc) *(edi+0xc)) # Block-var + (push *(ebp+0xc) *(edi+0x10)) # Block-var + (push *(ebp+0xc) 0) # false + # increment *Curr-block-depth + ff 0/subop/increment *Curr-block-depth + { +$parse-mu-block:line-loop: + # line = read-line-buffered(in) + (clear-stream %ecx) + (read-line-buffered *(ebp+8) %ecx) +#? (write-buffered Stderr "line: ") +#? (write-stream-data Stderr %ecx) +#? #? (write-buffered Stderr Newline) # line has its own newline +#? (flush Stderr) +#? (rewind-stream %ecx) + # if (line->write == 0) break + 81 7/subop/compare *ecx 0/imm32 + 0f 84/jump-if-= break/disp32 +#? (write-buffered Stderr "vars:\n") +#? (dump-vars *(ebp+0xc)) + # word-slice = next-mu-token(line) + (next-mu-token %ecx %edx) +#? (write-buffered Stderr "word: ") +#? (write-slice-buffered Stderr %edx) +#? (write-buffered Stderr Newline) +#? (flush Stderr) + # if slice-empty?(word-slice) continue + (slice-empty? %edx) + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= loop/disp32 + # if (slice-starts-with?(word-slice, '#') continue + # . eax = *word-slice->start + 8b/-> *edx 0/r32/eax + 8a/copy-byte *eax 0/r32/AL + 81 4/subop/and %eax 0xff/imm32 + # . if (eax == '#') continue + 3d/compare-eax-and 0x23/imm32/hash + 0f 84/jump-if-= loop/disp32 + # if slice-equal?(word-slice, "{") + { +$parse-mu-block:check-for-block: + (slice-equal? %edx "{") + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (check-no-tokens-left %ecx) + # parse new block and append + # . var tmp/eax: (handle block) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %eax 4/r32/esp + # . + (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c)) + (append-to-block Heap %edi *eax *(eax+4)) + # . reclaim tmp + 81 0/subop/add %esp 8/imm32 + # . + e9/jump $parse-mu-block:line-loop/disp32 + } + # if slice-equal?(word-slice, "}") break +$parse-mu-block:check-for-end: + (slice-equal? %edx "}") + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= break/disp32 + # if slice-ends-with?(word-slice, ":") parse named block and append + { +$parse-mu-block:check-for-named-block: + # . eax = *(word-slice->end-1) + 8b/-> *(edx+4) 0/r32/eax + 48/decrement-eax + 8a/copy-byte *eax 0/r32/AL + 81 4/subop/and %eax 0xff/imm32 + # . if (eax != ':') break + 3d/compare-eax-and 0x3a/imm32/colon + 0f 85/jump-if-!= break/disp32 + # TODO: error-check the rest of 'line' + # + # skip ':' + ff 1/subop/decrement *(edx+4) # Slice-end + # var tmp/eax: (handle block) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %eax 4/r32/esp + # + (parse-mu-named-block %edx *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c)) + (append-to-block Heap %edi *eax *(eax+4)) + # reclaim tmp + 81 0/subop/add %esp 8/imm32 + # + e9/jump $parse-mu-block:line-loop/disp32 + } + # if slice-equal?(word-slice, "var") + { +$parse-mu-block:check-for-var: + (slice-equal? %edx "var") + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + # var tmp/eax: (handle block) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %eax 4/r32/esp + # + (parse-mu-var-def %ecx *(ebp+0xc) %eax *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c)) + (append-to-block Heap %edi *eax *(eax+4)) + # reclaim tmp + 81 0/subop/add %esp 8/imm32 + # + e9/jump $parse-mu-block:line-loop/disp32 + } +$parse-mu-block:regular-stmt: + # otherwise + # var tmp/eax: (handle block) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %eax 4/r32/esp + # + (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c)) + (append-to-block Heap %edi *eax *(eax+4)) + # reclaim tmp + 81 0/subop/add %esp 8/imm32 + # + e9/jump loop/disp32 + } # end line loop + (clean-up-blocks *(ebp+0xc) *Curr-block-depth *(ebp+0x10)) + # decrement *Curr-block-depth + ff 1/subop/decrement *Curr-block-depth + # pop(vars) + (pop *(ebp+0xc)) # => eax + (pop *(ebp+0xc)) # => eax + (pop *(ebp+0xc)) # => eax +$parse-mu-block:end: + # . reclaim locals + 81 0/subop/add %esp 0x214/imm32 + # . restore registers + 5f/pop-to-edi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$parse-mu-block:abort: + # error("'{' or '}' should be on its own line, but got '") + (write-buffered *(ebp+0x18) "'{' or '}' should be on its own line, but got '") + (rewind-stream %ecx) + (write-stream-data *(ebp+0x18) %ecx) + (write-buffered *(ebp+0x18) "'\n") + (flush *(ebp+0x18)) + (stop *(ebp+0x1c) 1) + # never gets here + +new-block-name: # fn: (addr function), out: (addr handle var) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + # var n/ecx: int = len(fn->name) + 10 for an int + 2 for '$:' + 8b/-> *(ebp+8) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + 8b/-> *eax 0/r32/eax # String-size + 05/add-to-eax 0xd/imm32 # 10 + 2 for '$:' + 89/<- %ecx 0/r32/eax + # var name/edx: (stream byte n) + 29/subtract-from %esp 1/r32/ecx + ff 6/subop/push %ecx + 68/push 0/imm32/read + 68/push 0/imm32/write + 89/<- %edx 4/r32/esp + (clear-stream %edx) + # eax = fn->name + 8b/-> *(ebp+8) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + # construct result using Next-block-index (and increment it) + (write %edx "$") + (write %edx %eax) + (write %edx ":") + (write-int32-hex %edx *Next-block-index) + ff 0/subop/increment *Next-block-index + # var s/eax: slice = {name->data, name->data + name->write} (clobbering edx) + # . eax = name->write + 8b/-> *edx 0/r32/eax + # . edx = name->data + 8d/copy-address *(edx+0xc) 2/r32/edx + # . eax = name->write + name->data + 01/add-to %eax 2/r32/edx + # . push {edx, eax} + ff 6/subop/push %eax + ff 6/subop/push %edx + 89/<- %eax 4/r32/esp + # out = new literal(s) + (new-literal Heap %eax *(ebp+0xc)) +#? 8b/-> *(ebp+0xc) 0/r32/eax +#? (write-buffered Stderr "type allocid in caller after new-literal: ") +#? (write-int32-hex-buffered Stderr *(eax+8)) +#? (write-buffered Stderr " for var ") +#? (write-int32-hex-buffered Stderr %eax) +#? (write-buffered Stderr Newline) +#? (flush Stderr) +$new-block-name:end: + # . reclaim locals + 81 0/subop/add %ecx 0xc/imm32 # name.{read/write/len} + 81 0/subop/add %ecx 8/imm32 # slice + 01/add-to %esp 1/r32/ecx + # . restore registers + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +check-no-tokens-left: # line: (addr stream byte) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + # var s/ecx: slice + 68/push 0/imm32/end + 68/push 0/imm32/start + 89/<- %ecx 4/r32/esp + # + (next-mu-token *(ebp+8) %ecx) + # if slice-empty?(s) return + (slice-empty? %ecx) + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= $check-no-tokens-left:end/disp8 + # if (slice-starts-with?(s, '#') return + # . eax = *s->start + 8b/-> *edx 0/r32/eax + 8a/copy-byte *eax 0/r32/AL + 81 4/subop/and %eax 0xff/imm32 + # . if (eax == '#') continue + 3d/compare-eax-and 0x23/imm32/hash + 74/jump-if-= $check-no-tokens-left:end/disp8 + # abort + (write-buffered Stderr "'{' or '}' should be on its own line, but got '") + (rewind-stream %ecx) + (write-stream 2 %ecx) + (write-buffered Stderr "'\n") + (flush Stderr) + # . syscall(exit, 1) + bb/copy-to-ebx 1/imm32 + e8/call syscall_exit/disp32 + # never gets here +$check-no-tokens-left:end: + # . reclaim locals + 81 0/subop/add %esp 8/imm32 + # . restore registers + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +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) + # pseudocode: + # var v: (handle var) + # new-literal(name, v) + # push(vars, {v, false}) + # parse-mu-block(in, vars, fn, out) + # pop(vars) + # out->tag = block + # out->var = v + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 57/push-edi + # var v/ecx: (handle var) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %ecx 4/r32/esp + # + (new-literal Heap *(ebp+8) %ecx) + # push(vars, v) + (push *(ebp+0x10) *ecx) + (push *(ebp+0x10) *(ecx+4)) + (push *(ebp+0x10) 0) # false + # + (parse-mu-block *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20)) + # pop v off vars + (pop *(ebp+0x10)) # => eax + (pop *(ebp+0x10)) # => eax + (pop *(ebp+0x10)) # => eax + # var out-addr/edi: (addr stmt) = lookup(*out) + 8b/-> *(ebp+0x18) 7/r32/edi + (lookup *edi *(edi+4)) # => eax + 89/<- %edi 0/r32/eax + # out-addr->tag = named-block + c7 0/subop/copy *edi 0/imm32/block # Stmt-tag + # out-addr->var = v + 8b/-> *ecx 0/r32/eax + 89/<- *(edi+0xc) 0/r32/eax # Block-var + 8b/-> *(ecx+4) 0/r32/eax + 89/<- *(edi+0x10) 0/r32/eax # Block-var +$parse-mu-named-block:end: + # . reclaim locals + 81 0/subop/add %esp 8/imm32 + # . restore registers + 5f/pop-to-edi + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +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) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 56/push-esi + 57/push-edi + # edi = out + 8b/-> *(ebp+0x10) 7/r32/edi + # var word-slice/ecx: slice + 68/push 0/imm32/end + 68/push 0/imm32/start + 89/<- %ecx 4/r32/esp + # var v/edx: (handle var) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + # v = parse-var-with-type(next-mu-token(line)) + (next-mu-token *(ebp+8) %ecx) + { + # just for tests, support null fn + 8b/-> *(ebp+0x14) 0/r32/eax + 3d/compare-eax-and 0/imm32 + 74/jump-if-= break/disp8 + (lookup *eax *(eax+4)) # Var-name Var-name => eax + } + (parse-var-with-type %ecx *(ebp+8) %edx %eax *(ebp+0x18) *(ebp+0x1c)) + # var v-addr/esi: (addr var) + (lookup *edx *(edx+4)) # => eax + 89/<- %esi 0/r32/eax + # v->block-depth = *Curr-block-depth + 8b/-> *Curr-block-depth 0/r32/eax + 89/<- *(esi+0x10) 0/r32/eax # Var-block-depth + # either v has no register and there's no more to this line + 81 7/subop/compare *(esi+0x18) 0/imm32 + { + 75/jump-if-!= break/disp8 + # if v-addr->type == byte, abort + (lookup *(esi+8) *(esi+0xc)) # Var-type Var-type => eax + (is-simple-mu-type? %eax 8) # byte => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $parse-mu-var-def:error-byte-on-stack/disp32 + # ensure that there's nothing else on this line + (next-mu-token *(ebp+8) %ecx) + (slice-empty? %ecx) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $parse-mu-var-def:error2/disp32 + # + (new-var-def Heap *edx *(edx+4) %edi) + e9/jump $parse-mu-var-def:update-vars/disp32 + } + # or v has a register and there's more to this line + { + 0f 84/jump-if-= break/disp32 + # if v-addr->type == byte, check for unsupported registers + { + (lookup *(esi+8) *(esi+0xc)) # Var-type Var-type => eax + (is-simple-mu-type? %eax 8) # byte => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (lookup *(esi+0x18) *(esi+0x1c)) # => eax + (string-equal? %eax "esi") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $parse-mu-var-def:error-byte-registers/disp32 + (lookup *(esi+0x18) *(esi+0x1c)) # => eax + (string-equal? %eax "edi") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $parse-mu-var-def:error-byte-registers/disp32 + } + # TODO: vars of type 'byte' should only be initialized by clearing to 0 + # ensure that the next word is '<-' + (next-mu-token *(ebp+8) %ecx) + (slice-equal? %ecx "<-") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $parse-mu-var-def:error1/disp32 + # + (new-reg-var-def Heap *edx *(edx+4) %edi) + (lookup *edi *(edi+4)) # => eax + (add-operation-and-inputs-to-stmt %eax *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c)) + } +$parse-mu-var-def:update-vars: + # push 'v' at end of function + (push *(ebp+0xc) *edx) + (push *(ebp+0xc) *(edx+4)) + (push *(ebp+0xc) 0) # Live-var-register-spilled is unused during parsing +$parse-mu-var-def:end: + # . reclaim locals + 81 0/subop/add %esp 0x10/imm32 + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$parse-mu-var-def:error1: + (rewind-stream *(ebp+8)) + # error("register variable requires a valid instruction to initialize but got '" line "'\n") + (write-buffered *(ebp+0x18) "register variable requires a valid instruction to initialize but got '") + (flush *(ebp+0x18)) + (write-stream-data *(ebp+0x18) *(ebp+8)) + (write-buffered *(ebp+0x18) "'\n") + (flush *(ebp+0x18)) + (stop *(ebp+0x1c) 1) + # never gets here + +$parse-mu-var-def:error2: + # error("fn " fn ": var " var ": variables on the stack can't take an initializer\n") + (write-buffered *(ebp+0x18) "fn ") + 8b/-> *(ebp+0x14) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x18) %eax) + (write-buffered *(ebp+0x18) ": var ") + # var v-addr/eax: (addr var) = lookup(v) + (lookup *edx *(edx+4)) # => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x18) %eax) + (write-buffered *(ebp+0x18) ": variables on the stack can't take an initializer\n") + (flush *(ebp+0x18)) + (stop *(ebp+0x1c) 1) + # never gets here + +$parse-mu-var-def:error-byte-on-stack: + # error("fn " fn ": var '" var "' of type 'byte' cannot be on the stack\n") + (write-buffered *(ebp+0x18) "fn ") + 8b/-> *(ebp+0x14) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x18) %eax) + (write-buffered *(ebp+0x18) ": var '") + # var v-addr/eax: (addr var) = lookup(v) + (lookup *edx *(edx+4)) # => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x18) %eax) + (write-buffered *(ebp+0x18) "' of type 'byte' cannot be on the stack\n") + (flush *(ebp+0x18)) + (stop *(ebp+0x1c) 1) + # never gets here + +$parse-mu-var-def:error-byte-registers: + # error("fn " fn ": var '" var "' of type 'byte' cannot be in esi or edi\n") + (write-buffered *(ebp+0x18) "fn ") + 8b/-> *(ebp+0x14) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x18) %eax) + (write-buffered *(ebp+0x18) ": var '") + # var v-addr/eax: (addr var) = lookup(v) + (lookup *edx *(edx+4)) # => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x18) %eax) + (write-buffered *(ebp+0x18) "' of type 'byte' cannot be in esi or edi\n") + (flush *(ebp+0x18)) + (stop *(ebp+0x1c) 1) + # never gets here + +test-parse-mu-var-def: + # 'var n: int' + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + 8b/-> *Primitive-type-ids 0/r32/eax + 89/<- *Type-id 0/r32/eax # stream-write + (clear-stream _test-input-stream) + (write _test-input-stream "n: int\n") # caller has consumed the 'var' + c7 0/subop/copy *Curr-block-depth 1/imm32 + # var out/esi: (handle stmt) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %esi 4/r32/esp + # var vars/ecx: (stack (addr var) 16) + 81 5/subop/subtract %esp 0xc0/imm32 + 68/push 0xc0/imm32/size + 68/push 0/imm32/top + 89/<- %ecx 4/r32/esp + (clear-stack %ecx) + # convert + (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0) + # var out-addr/esi: (addr stmt) + (lookup *esi *(esi+4)) # => eax + 89/<- %esi 0/r32/eax + # + (check-ints-equal *esi 2 "F - test-parse-mu-var-def/tag") # Stmt-tag is var-def + # var v/ecx: (addr var) = lookup(out->var) + (lookup *(esi+4) *(esi+8)) # Vardef-var Vardef-var => eax + 89/<- %ecx 0/r32/eax + # v->name + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (check-strings-equal %eax "n" "F - test-parse-mu-var-def/var-name") + # v->register + (check-ints-equal *(ecx+0x18) 0 "F - test-parse-mu-var-def/var-register") # Var-register + # v->block-depth + (check-ints-equal *(ecx+0x10) 1 "F - test-parse-mu-var-def/output-block-depth") # Var-block-depth + # v->type == int + (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + (check-ints-equal *eax 1 "F - test-parse-mu-var-def/var-type:0") # Type-tree-is-atom + (check-ints-equal *(eax+4) 1 "F - test-parse-mu-var-def/var-type:1") # Type-tree-value + (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-var-def/var-type:2") # Type-tree-right + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-parse-mu-reg-var-def: + # 'var n/eax: int <- copy 0' + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + 8b/-> *Primitive-type-ids 0/r32/eax + 89/<- *Type-id 0/r32/eax # stream-write + (clear-stream _test-input-stream) + (write _test-input-stream "n/eax: int <- copy 0\n") # caller has consumed the 'var' + c7 0/subop/copy *Curr-block-depth 1/imm32 + # var out/esi: (handle stmt) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %esi 4/r32/esp + # var vars/ecx: (stack (addr var) 16) + 81 5/subop/subtract %esp 0xc0/imm32 + 68/push 0xc0/imm32/size + 68/push 0/imm32/top + 89/<- %ecx 4/r32/esp + (clear-stack %ecx) + # convert + (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0) + # var out-addr/esi: (addr stmt) + (lookup *esi *(esi+4)) # => eax + 89/<- %esi 0/r32/eax + # + (check-ints-equal *esi 3 "F - test-parse-mu-reg-var-def/tag") # Stmt-tag is reg-var-def + # var v/ecx: (addr var) = lookup(out->outputs->value) + # . eax: (addr stmt-var) = lookup(out->outputs) + (lookup *(esi+0x14) *(esi+0x18)) # Regvardef-outputs Regvardef-outputs => eax + # . + (check-ints-equal *(eax+8) 0 "F - test-parse-mu-reg-var-def/single-output") # Stmt-var-next + # . eax: (addr var) = lookup(eax->value) + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + # . ecx = eax + 89/<- %ecx 0/r32/eax + # v->name + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (check-strings-equal %eax "n" "F - test-parse-mu-reg-var-def/output-name") # Var-name + # v->register + (lookup *(ecx+0x18) *(ecx+0x1c)) # Var-register Var-register => eax + (check-strings-equal %eax "eax" "F - test-parse-mu-reg-var-def/output-register") + # v->block-depth + (check-ints-equal *(ecx+0x10) 1 "F - test-parse-mu-reg-var-def/output-block-depth") # Var-block-depth + # v->type == int + (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + (check-ints-equal *eax 1 "F - test-parse-mu-reg-var-def/output-type:0") # Type-tree-is-atom + (check-ints-equal *(eax+4) 1 "F - test-parse-mu-reg-var-def/output-type:1") # Type-tree-value + (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-reg-var-def/output-type:2") # Type-tree-right + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +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) + # pseudocode: + # var name: slice + # allocate(Heap, Stmt-size, out) + # var out-addr: (addr stmt) = lookup(*out) + # out-addr->tag = stmt + # if stmt-has-outputs?(line) + # while true + # name = next-mu-token(line) + # if (name == '<-') break + # assert(is-identifier?(name)) + # var v: (handle var) = lookup-var(name, vars) + # out-addr->outputs = append(v, out-addr->outputs) + # add-operation-and-inputs-to-stmt(out-addr, line, vars) + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 57/push-edi + # var name/ecx: slice + 68/push 0/imm32/end + 68/push 0/imm32/start + 89/<- %ecx 4/r32/esp + # var is-deref?/edx: boolean = false + ba/copy-to-edx 0/imm32/false + # var v: (handle var) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %ebx 4/r32/esp + # + (allocate Heap *Stmt-size *(ebp+0x14)) + # var out-addr/edi: (addr stmt) = lookup(*out) + 8b/-> *(ebp+0x14) 7/r32/edi + (lookup *edi *(edi+4)) # => eax + 89/<- %edi 0/r32/eax + # out-addr->tag = 1/stmt + c7 0/subop/copy *edi 1/imm32/stmt1 # Stmt-tag + { + (stmt-has-outputs? *(ebp+8)) + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= break/disp32 + { +$parse-mu-stmt:read-outputs: + # name = next-mu-token(line) + (next-mu-token *(ebp+8) %ecx) + # if slice-empty?(word-slice) break + (slice-empty? %ecx) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= break/disp32 + # if (name == "<-") break + (slice-equal? %ecx "<-") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= break/disp32 + # if slice-starts-with?(name, "*") abort + 8b/-> *ecx 0/r32/eax # Slice-start + 8a/copy-byte *eax 0/r32/AL + 81 4/subop/and %eax 0xff/imm32 + 3d/compare-eax-and 0x2a/imm32/asterisk + 0f 84/jump-if-= $parse-mu-stmt:error-output-dereferenced/disp32 + # assert(is-identifier?(name)) + (is-identifier? %ecx) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $parse-mu-stmt:abort/disp32 + # + (lookup-var %ecx *(ebp+0xc) %ebx *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c)) + 8d/copy-address *(edi+0x14) 0/r32/eax # Stmt1-outputs + (append-stmt-var Heap *ebx *(ebx+4) *(edi+0x14) *(edi+0x18) 0 %eax) # Stmt1-outputs + # + e9/jump loop/disp32 + } + } + (add-operation-and-inputs-to-stmt %edi *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c)) +$parse-mu-stmt:end: + # . reclaim locals + 81 0/subop/add %esp 0x10/imm32 + # . restore registers + 5f/pop-to-edi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$parse-mu-stmt:abort: + # error("invalid identifier '" name "'\n") + (write-buffered *(ebp+0x18) "fn ") + 8b/-> *(ebp+0x10) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x18) %eax) + (write-buffered *(ebp+0x18) ": invalid identifier '") + (write-slice-buffered *(ebp+0x18) %ecx) + (write-buffered *(ebp+0x18) "'\n") + (flush *(ebp+0x18)) + (stop *(ebp+0x1c) 1) + # never gets here + +$parse-mu-stmt:error-output-dereferenced: + # error("invalid identifier '" name "'\n") + (write-buffered *(ebp+0x18) "fn ") + 8b/-> *(ebp+0x10) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x18) %eax) + (write-buffered *(ebp+0x18) ": output '") + (write-slice-buffered *(ebp+0x18) %ecx) + (write-buffered *(ebp+0x18) "' should write to a register, and therefore cannot be dereferenced\n") + (flush *(ebp+0x18)) + (stop *(ebp+0x1c) 1) + # never gets here + +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) + # pseudocode: + # stmt->name = slice-to-string(next-mu-token(line)) + # while true + # name = next-mu-token(line) + # v = lookup-var-or-literal(name) + # stmt->inouts = append(v, stmt->inouts) + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + 57/push-edi + # edi = stmt + 8b/-> *(ebp+8) 7/r32/edi + # var name/ecx: slice + 68/push 0/imm32/end + 68/push 0/imm32/start + 89/<- %ecx 4/r32/esp + # var is-deref?/edx: boolean = false + ba/copy-to-edx 0/imm32/false + # var v/esi: (handle var) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %esi 4/r32/esp +$add-operation-and-inputs-to-stmt:read-operation: + (next-mu-token *(ebp+0xc) %ecx) + 8d/copy-address *(edi+4) 0/r32/eax # Stmt1-operation or Regvardef-operationStmt1-operation or Regvardef-operation + (slice-to-string Heap %ecx %eax) + # var is-get?/ebx: boolean = (name == "get") + (slice-equal? %ecx "get") # => eax + 89/<- %ebx 0/r32/eax + { +$add-operation-and-inputs-to-stmt:read-inouts: + # name = next-mu-token(line) + (next-mu-token *(ebp+0xc) %ecx) + # if slice-empty?(word-slice) break + (slice-empty? %ecx) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= break/disp32 + # if (name == "<-") abort + (slice-equal? %ecx "<-") + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $add-operation-and-inputs-to-stmt:abort/disp32 + # if (is-get? && second operand) lookup or create offset + { + 81 7/subop/compare %ebx 0/imm32/false + 74/jump-if-= break/disp8 + (lookup *(edi+0xc) *(edi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 3d/compare-eax-and 0/imm32 + 74/jump-if-= break/disp8 + (lookup-or-create-constant %eax %ecx %esi) +#? (lookup *esi *(esi+4)) +#? (write-buffered Stderr "creating new output var ") +#? (write-int32-hex-buffered Stderr %eax) +#? (write-buffered Stderr " for field called ") +#? (write-slice-buffered Stderr %ecx) +#? (write-buffered Stderr "; var name ") +#? (lookup *eax *(eax+4)) # Var-name +#? (write-buffered Stderr %eax) +#? (write-buffered Stderr Newline) +#? (flush Stderr) + e9/jump $add-operation-and-inputs-to-stmt:save-var/disp32 + } + # is-deref? = false + ba/copy-to-edx 0/imm32/false + # if (slice-starts-with?(name, '*')) ++name->start and set is-deref? + 8b/-> *ecx 0/r32/eax # Slice-start + 8a/copy-byte *eax 0/r32/AL + 81 4/subop/and %eax 0xff/imm32 + 3d/compare-eax-and 0x2a/imm32/asterisk + { + 75/jump-if-!= break/disp8 +$add-operation-and-inputs-to-stmt:inout-is-deref: + ff 0/subop/increment *ecx + ba/copy-to-edx 1/imm32/true + } + (lookup-var-or-literal %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c)) + # if (is-deref?) some additional checks + 81 7/subop/compare %edx 0/imm32/false + { + 74/jump-if-= break/disp8 + # if var is not in register, abort + (lookup *esi *(esi+4)) # => eax + 81 7/subop/compare *(eax+0x18) 0/imm32 # Var-register + 0f 84/jump-if-= $add-operation-and-inputs-to-stmt:error-deref-on-stack/disp32 + # if var is not an address, abort + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + (is-mu-addr-type? %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $add-operation-and-inputs-to-stmt:error-deref-non-addr/disp32 + } +$add-operation-and-inputs-to-stmt:save-var: + 8d/copy-address *(edi+0xc) 0/r32/eax + (append-stmt-var Heap *esi *(esi+4) *(edi+0xc) *(edi+0x10) %edx %eax) # Stmt1-inouts or Regvardef-inouts + # + e9/jump loop/disp32 + } +$add-operation-and-inputs-to-stmt:end: + # . reclaim locals + 81 0/subop/add %esp 0x10/imm32 + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$add-operation-and-inputs-to-stmt:abort: + # error("fn ___: invalid identifier in '" line "'\n") + (write-buffered *(ebp+0x18) "fn ") + 8b/-> *(ebp+0x14) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x18) %eax) + (rewind-stream *(ebp+0xc)) + (write-buffered *(ebp+0x18) ": invalid identifier in '") + (write-stream-data *(ebp+0x18) *(ebp+0xc)) + (write-buffered *(ebp+0x18) "'\n") + (flush *(ebp+0x18)) + (stop *(ebp+0x1c) 1) + # never gets here + +$add-operation-and-inputs-to-stmt:error-deref-on-stack: + # error("fn ___: cannot dereference var ___ on stack\n") + (write-buffered *(ebp+0x18) "fn ") + 8b/-> *(ebp+0x14) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x18) %eax) + (rewind-stream *(ebp+0xc)) + (write-buffered *(ebp+0x18) ": cannot dereference var '") + (lookup *esi *(esi+4)) # => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x18) %eax) + (write-buffered *(ebp+0x18) "' on stack\n") + (flush *(ebp+0x18)) + (stop *(ebp+0x1c) 1) + # never gets here + +$add-operation-and-inputs-to-stmt:error-deref-non-addr: + # error("fn ___: cannot dereference non-addr var ___\n") + (write-buffered *(ebp+0x18) "fn ") + 8b/-> *(ebp+0x14) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x18) %eax) + (rewind-stream *(ebp+0xc)) + (write-buffered *(ebp+0x18) ": cannot dereference non-addr var '") + (lookup *esi *(esi+4)) # => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x18) %eax) + (write-buffered *(ebp+0x18) "'\n") + (flush *(ebp+0x18)) + (stop *(ebp+0x1c) 1) + # never gets here + +stmt-has-outputs?: # line: (addr stream byte) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # var word-slice/ecx: slice + 68/push 0/imm32/end + 68/push 0/imm32/start + 89/<- %ecx 4/r32/esp + # result = false + b8/copy-to-eax 0/imm32/false + (rewind-stream *(ebp+8)) + { + (next-mu-token *(ebp+8) %ecx) + # if slice-empty?(word-slice) break + (slice-empty? %ecx) + 3d/compare-eax-and 0/imm32/false + b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) + 0f 85/jump-if-!= break/disp32 + # if slice-starts-with?(word-slice, '#') break + # . eax = *word-slice->start + 8b/-> *ecx 0/r32/eax + 8a/copy-byte *eax 0/r32/AL + 81 4/subop/and %eax 0xff/imm32 + # . if (eax == '#') break + 3d/compare-eax-and 0x23/imm32/hash + b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) + 0f 84/jump-if-= break/disp32 + # if slice-equal?(word-slice, '<-') return true + (slice-equal? %ecx "<-") + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= loop/disp8 + b8/copy-to-eax 1/imm32/true + } +$stmt-has-outputs:end: + (rewind-stream *(ebp+8)) + # . reclaim locals + 81 0/subop/add %esp 8/imm32 + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# if 'name' starts with a digit, create a new literal var for it +# otherwise return first 'name' from the top (back) of 'vars' and abort if not found +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) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 56/push-esi + # esi = name + 8b/-> *(ebp+8) 6/r32/esi + # if slice-empty?(name) abort + (slice-empty? %esi) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32 + # var c/ecx: byte = *name->start + 8b/-> *esi 1/r32/ecx + 8a/copy-byte *ecx 1/r32/CL + 81 4/subop/and %ecx 0xff/imm32 + # if (is-decimal-digit?(c) || c == '-') return new var(name) + { + 81 7/subop/compare %ecx 0x2d/imm32/dash + 74/jump-if-= $lookup-var-or-literal:literal/disp8 + (is-decimal-digit? %ecx) # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 +$lookup-var-or-literal:literal: + (new-literal-integer Heap %esi *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c)) + eb/jump $lookup-var-or-literal:end/disp8 + } + # else if (c == '"') return new var(name) + { + 81 7/subop/compare %ecx 0x22/imm32/dquote + 75/jump-if-!= break/disp8 +$lookup-var-or-literal:literal-string: + (new-literal-string Heap %esi *(ebp+0x10)) + eb/jump $lookup-var-or-literal:end/disp8 + } + # otherwise return lookup-var(name, vars) + { +$lookup-var-or-literal:var: + (lookup-var %esi *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c)) + } +$lookup-var-or-literal:end: + # . restore registers + 5e/pop-to-esi + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$lookup-var-or-literal:abort: + (write-buffered *(ebp+0x18) "fn ") + 8b/-> *(ebp+0x14) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x18) %eax) + (write-buffered *(ebp+0x18) ": empty variable!") + (flush *(ebp+0x18)) + (stop *(ebp+0x1c) 1) + # never gets here + +# return first 'name' from the top (back) of 'vars' and abort if not found +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) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + # + (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c)) + # if (*out == 0) abort + 8b/-> *(ebp+0x10) 0/r32/eax + 81 7/subop/compare *eax 0/imm32 + 74/jump-if-= $lookup-var:abort/disp8 +$lookup-var:end: + # . restore registers + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$lookup-var:abort: + (write-buffered *(ebp+0x18) "fn ") + 8b/-> *(ebp+0x14) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x18) %eax) + (write-buffered *(ebp+0x18) ": unknown variable '") + (write-slice-buffered *(ebp+0x18) *(ebp+8)) + (write-buffered *(ebp+0x18) "'\n") + (flush *(ebp+0x18)) + (stop *(ebp+0x1c) 1) + # never gets here + +# return first 'name' from the top (back) of 'vars', and 0/null if not found +# ensure that 'name' if in a register is the topmost variable in that register +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) + # pseudocode: + # var curr: (addr handle var) = &vars->data[vars->top - 12] + # var min = vars->data + # while curr >= min + # var v: (handle var) = *curr + # if v->name == name + # return + # curr -= 12 + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + 57/push-edi + # clear out + (zero-out *(ebp+0x10) *Handle-size) + # esi = vars + 8b/-> *(ebp+0xc) 6/r32/esi + # ebx = vars->top + 8b/-> *esi 3/r32/ebx + # if (vars->top > vars->size) abort + 3b/compare<- *(esi+4) 0/r32/eax + 0f 8f/jump-if-> $lookup-var-helper:error1/disp32 + # var min/edx: (addr handle var) = vars->data + 8d/copy-address *(esi+8) 2/r32/edx + # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12] + 8d/copy-address *(esi+ebx-4) 3/r32/ebx # vars + 8 + vars->type - 12 + # var var-in-reg/edi: 16 addrs + 68/push 0/imm32 + 68/push 0/imm32 + 68/push 0/imm32 + 68/push 0/imm32 + 68/push 0/imm32 + 68/push 0/imm32 + 68/push 0/imm32 + 68/push 0/imm32 + 68/push 0/imm32 + 68/push 0/imm32 + 68/push 0/imm32 + 68/push 0/imm32 + 68/push 0/imm32 + 68/push 0/imm32 + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edi 4/r32/esp + { +$lookup-var-helper:loop: + # if (curr < min) return + 39/compare %ebx 2/r32/edx + 0f 82/jump-if-addr< break/disp32 + # var v/ecx: (addr var) = lookup(*curr) + (lookup *ebx *(ebx+4)) # => eax + 89/<- %ecx 0/r32/eax + # var vn/eax: (addr array byte) = lookup(v->name) + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + # if (vn == name) return curr + (slice-equal? *(ebp+8) %eax) # => eax + 3d/compare-eax-and 0/imm32/false + { + 74/jump-if-= break/disp8 +$lookup-var-helper:found: + # var vr/eax: (addr array byte) = lookup(v->register) + (lookup *(ecx+0x18) *(ecx+0x1c)) # Var-register Var-register => eax + 3d/compare-eax-and 0/imm32 + { + 74/jump-if-= break/disp8 +$lookup-var-helper:found-register: + # var reg/eax: int = get(Registers, vr) + (get Mu-registers-unique %eax 0xc "Mu-registers-unique") # => eax + 8b/-> *eax 0/r32/eax + # if (var-in-reg[reg]) error + 8b/-> *(edi+eax<<2) 0/r32/eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $lookup-var-helper:error2/disp32 + } +$lookup-var-helper:return: + # esi = out + 8b/-> *(ebp+0x10) 6/r32/esi + # *out = *curr + 8b/-> *ebx 0/r32/eax + 89/<- *esi 0/r32/eax + 8b/-> *(ebx+4) 0/r32/eax + 89/<- *(esi+4) 0/r32/eax + # return + eb/jump $lookup-var-helper:end/disp8 + } + # 'name' not yet found; update var-in-reg if v in register + # . var vr/eax: (addr array byte) = lookup(v->register) + (lookup *(ecx+0x18) *(ecx+0x1c)) # Var-register Var-register => eax + # . if (vr == 0) continue + 3d/compare-eax-and 0/imm32 + 74/jump-if-= $lookup-var-helper:continue/disp8 + # . var reg/eax: int = get(Registers, vr) + (get Mu-registers-unique %eax 0xc "Mu-registers-unique") # => eax + 8b/-> *eax 0/r32/eax + # . var-in-reg[reg] = v + 89/<- *(edi+eax<<2) 1/r32/ecx +$lookup-var-helper:continue: + # curr -= 12 + 81 5/subop/subtract %ebx 0xc/imm32 + e9/jump loop/disp32 + } +$lookup-var-helper:end: + # . reclaim locals + 81 0/subop/add %esp 0x40/imm32 + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$lookup-var-helper:error1: + (write-buffered *(ebp+0x18) "fn ") + 8b/-> *(ebp+0x14) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x18) %eax) + (write-buffered *(ebp+0x18) ": malformed stack when looking up '") + (write-slice-buffered *(ebp+0x18) *(ebp+8)) + (write-buffered *(ebp+0x18) "'\n") + (flush *(ebp+0x18)) + (stop *(ebp+0x1c) 1) + # never gets here + +$lookup-var-helper:error2: + # eax contains the conflicting var at this point + (write-buffered *(ebp+0x18) "fn ") + 50/push-eax + 8b/-> *(ebp+0x14) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x18) %eax) + 58/pop-eax + (write-buffered *(ebp+0x18) ": register ") + 50/push-eax + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + (write-buffered *(ebp+0x18) %eax) + 58/pop-to-eax + (write-buffered *(ebp+0x18) " reads var '") + (write-slice-buffered *(ebp+0x18) *(ebp+8)) + (write-buffered *(ebp+0x18) "' after writing var '") + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x18) %eax) + (write-buffered *(ebp+0x18) "'\n") + (flush *(ebp+0x18)) + (stop *(ebp+0x1c) 1) + # never gets here + +dump-vars: # vars: (addr stack live-var) + # pseudocode: + # var curr: (addr handle var) = &vars->data[vars->top - 12] + # var min = vars->data + # while curr >= min + # var v: (handle var) = *curr + # print v + # curr -= 12 + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 52/push-edx + 53/push-ebx + 56/push-esi + # esi = vars + 8b/-> *(ebp+8) 6/r32/esi + # ebx = vars->top + 8b/-> *esi 3/r32/ebx + # var min/edx: (addr handle var) = vars->data + 8d/copy-address *(esi+8) 2/r32/edx + # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12] + 8d/copy-address *(esi+ebx-4) 3/r32/ebx # vars + 8 + vars->type - 12 + { +$dump-vars:loop: + # if (curr < min) return + 39/compare %ebx 2/r32/edx + 0f 82/jump-if-addr< break/disp32 + # + (write-buffered Stderr " var@") + (dump-var 2 %ebx) + # curr -= 12 + 81 5/subop/subtract %ebx 0xc/imm32 + e9/jump loop/disp32 + } +$dump-vars:end: + # . restore registers + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +== data +# Like Registers, but no esp or ebp +Mu-registers: # (addr stream {(handle array byte), int}) + # a table is a stream + 0xa8/imm32/write + 0/imm32/read + 0xa8/imm32/length + # data + # general-purpose registers + # it is perfectly ok to use fake alloc-ids -- as long as you never try to reclaim them + 0x11/imm32/alloc-id $Mu-register-eax/imm32 0/imm32 + 0x11/imm32/alloc-id $Mu-register-ecx/imm32 1/imm32 + 0x11/imm32/alloc-id $Mu-register-edx/imm32 2/imm32 + 0x11/imm32/alloc-id $Mu-register-ebx/imm32 3/imm32 + 0x11/imm32/alloc-id $Mu-register-esi/imm32 6/imm32 + 0x11/imm32/alloc-id $Mu-register-edi/imm32 7/imm32 + # floating-point registers + 0x11/imm32/alloc-id $Mu-register-xmm0/imm32 0/imm32 + 0x11/imm32/alloc-id $Mu-register-xmm1/imm32 1/imm32 + 0x11/imm32/alloc-id $Mu-register-xmm2/imm32 2/imm32 + 0x11/imm32/alloc-id $Mu-register-xmm3/imm32 3/imm32 + 0x11/imm32/alloc-id $Mu-register-xmm4/imm32 4/imm32 + 0x11/imm32/alloc-id $Mu-register-xmm5/imm32 5/imm32 + 0x11/imm32/alloc-id $Mu-register-xmm6/imm32 6/imm32 + 0x11/imm32/alloc-id $Mu-register-xmm7/imm32 7/imm32 + +# Like Mu-registers, but with unique codes for integer and floating-point +# registers. +# Don't use this for code-generation, only for checking. +Mu-registers-unique: # (addr stream {(handle array byte), int}) + # a table is a stream + 0xa8/imm32/write + 0/imm32/read + 0xa8/imm32/length + # data + # general-purpose registers + 0x11/imm32/alloc-id $Mu-register-eax/imm32 0/imm32 + 0x11/imm32/alloc-id $Mu-register-ecx/imm32 1/imm32 + 0x11/imm32/alloc-id $Mu-register-edx/imm32 2/imm32 + 0x11/imm32/alloc-id $Mu-register-ebx/imm32 3/imm32 + 0x11/imm32/alloc-id $Mu-register-esi/imm32 6/imm32 + 0x11/imm32/alloc-id $Mu-register-edi/imm32 7/imm32 + # floating-point registers + 0x11/imm32/alloc-id $Mu-register-xmm0/imm32 8/imm32 + 0x11/imm32/alloc-id $Mu-register-xmm1/imm32 9/imm32 + 0x11/imm32/alloc-id $Mu-register-xmm2/imm32 0xa/imm32 + 0x11/imm32/alloc-id $Mu-register-xmm3/imm32 0xb/imm32 + 0x11/imm32/alloc-id $Mu-register-xmm4/imm32 0xc/imm32 + 0x11/imm32/alloc-id $Mu-register-xmm5/imm32 0xd/imm32 + 0x11/imm32/alloc-id $Mu-register-xmm6/imm32 0xe/imm32 + 0x11/imm32/alloc-id $Mu-register-xmm7/imm32 0xf/imm32 + +$Mu-register-eax: + 0x11/imm32/alloc-id + 3/imm32/size + 0x65/e 0x61/a 0x78/x + +$Mu-register-ecx: + 0x11/imm32/alloc-id + 3/imm32/size + 0x65/e 0x63/c 0x78/x + +$Mu-register-edx: + 0x11/imm32/alloc-id + 3/imm32/size + 0x65/e 0x64/d 0x78/x + +$Mu-register-ebx: + 0x11/imm32/alloc-id + 3/imm32/size + 0x65/e 0x62/b 0x78/x + +$Mu-register-esi: + 0x11/imm32/alloc-id + 3/imm32/size + 0x65/e 0x73/s 0x69/i + +$Mu-register-edi: + 0x11/imm32/alloc-id + 3/imm32/size + 0x65/e 0x64/d 0x69/i + +$Mu-register-xmm0: + 0x11/imm32/alloc-id:fake:payload + # "xmm0" + 0x4/imm32/size + 0x78/x 0x6d/m 0x6d/m 0x30/0 + +$Mu-register-xmm1: + 0x11/imm32/alloc-id:fake:payload + # "xmm1" + 0x4/imm32/size + 0x78/x 0x6d/m 0x6d/m 0x31/1 + +$Mu-register-xmm2: + 0x11/imm32/alloc-id:fake:payload + # "xmm2" + 0x4/imm32/size + 0x78/x 0x6d/m 0x6d/m 0x32/2 + +$Mu-register-xmm3: + 0x11/imm32/alloc-id:fake:payload + # "xmm3" + 0x4/imm32/size + 0x78/x 0x6d/m 0x6d/m 0x33/3 + +$Mu-register-xmm4: + 0x11/imm32/alloc-id:fake:payload + # "xmm4" + 0x4/imm32/size + 0x78/x 0x6d/m 0x6d/m 0x34/4 + +$Mu-register-xmm5: + 0x11/imm32/alloc-id:fake:payload + # "xmm5" + 0x4/imm32/size + 0x78/x 0x6d/m 0x6d/m 0x35/5 + +$Mu-register-xmm6: + 0x11/imm32/alloc-id:fake:payload + # "xmm6" + 0x4/imm32/size + 0x78/x 0x6d/m 0x6d/m 0x36/6 + +$Mu-register-xmm7: + 0x11/imm32/alloc-id:fake:payload + # "xmm7" + 0x4/imm32/size + 0x78/x 0x6d/m 0x6d/m 0x37/7 + +== code + +# push 'out' to 'vars' if not already there; it's assumed to be a fn output +maybe-define-var: # out: (handle var), vars: (addr stack live-var) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + # var out-addr/eax: (addr var) + (lookup *(ebp+8) *(ebp+0xc)) # => eax + # + (binding-exists? %eax *(ebp+0x10)) # => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= $maybe-define-var:end/disp8 + # otherwise update vars + (push *(ebp+0x10) *(ebp+8)) + (push *(ebp+0x10) *(ebp+0xc)) + (push *(ebp+0x10) 0) # 'out' is always a fn output; never spill it +$maybe-define-var:end: + # . restore registers + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# simpler version of lookup-var-helper +binding-exists?: # target: (addr var), vars: (addr stack live-var) -> result/eax: boolean + # pseudocode: + # var curr: (addr handle var) = &vars->data[vars->top - 12] + # var min = vars->data + # while curr >= min + # var v: (handle var) = *curr + # if v->name == target->name + # return true + # curr -= 12 + # return false + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + 52/push-edx + 56/push-esi + # var target-name/ecx: (addr array byte) = lookup(target->name) + 8b/-> *(ebp+8) 0/r32/eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + 89/<- %ecx 0/r32/eax + # esi = vars + 8b/-> *(ebp+0xc) 6/r32/esi + # eax = vars->top + 8b/-> *esi 0/r32/eax + # var min/edx: (addr handle var) = vars->data + 8d/copy-address *(esi+8) 2/r32/edx + # var curr/esi: (addr handle var) = &vars->data[vars->top - 12] + 8d/copy-address *(esi+eax-4) 6/r32/esi # vars + 8 + vars->type - 12 + { +$binding-exists?:loop: + # if (curr < min) return + 39/compare %esi 2/r32/edx + 0f 82/jump-if-addr< break/disp32 + # var v/eax: (addr var) = lookup(*curr) + (lookup *esi *(esi+4)) # => eax + # var vn/eax: (addr array byte) = lookup(v->name) + (lookup *eax *(eax+4)) # Var-name Var-name => eax + # if (vn == target-name) return true + (string-equal? %ecx %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= $binding-exists?:end/disp8 # eax already contains true + # curr -= 12 + 81 5/subop/subtract %esi 0xc/imm32 + e9/jump loop/disp32 + } + b8/copy-to-eax 0/imm32/false +$binding-exists?:end: + # . restore registers + 5e/pop-to-esi + 5a/pop-to-edx + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-parse-mu-stmt: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + 8b/-> *Primitive-type-ids 0/r32/eax + 89/<- *Type-id 0/r32/eax # stream-write + (clear-stream _test-input-stream) + (write _test-input-stream "increment n\n") + # var vars/ecx: (stack (addr var) 16) + 81 5/subop/subtract %esp 0xc0/imm32 + 68/push 0xc0/imm32/size + 68/push 0/imm32/top + 89/<- %ecx 4/r32/esp + (clear-stack %ecx) + # var v/edx: (handle var) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + # var s/eax: (handle array byte) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %eax 4/r32/esp + # v = new var("n") + (copy-array Heap "n" %eax) + (new-var Heap *eax *(eax+4) %edx) + # + (push %ecx *edx) + (push %ecx *(edx+4)) + (push %ecx 0) + # var out/eax: (handle stmt) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %eax 4/r32/esp + # convert + (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0) + # var out-addr/edx: (addr stmt) = lookup(*out) + (lookup *eax *(eax+4)) # => eax + 89/<- %edx 0/r32/eax + # out->tag + (check-ints-equal *edx 1 "F - test-parse-mu-stmt/tag") # Stmt-tag is Stmt1 + # out->operation + (lookup *(edx+4) *(edx+8)) # Stmt1-operation Stmt1-operation => eax + (check-strings-equal %eax "increment" "F - test-parse-mu-stmt/name") # Stmt1-operation + # out->inouts->value->name + # . eax = out->inouts + (lookup *(edx+0xc) *(edx+0x10)) # Stmt1-inouts Stmt1-inouts => eax + # . eax = out->inouts->value + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + # . eax = out->inouts->value->name + (lookup *eax *(eax+4)) # Var-name Var-name => eax + # . + (check-strings-equal %eax "n" "F - test-parse-mu-stmt/inout:0") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-parse-mu-stmt-with-comma: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + 8b/-> *Primitive-type-ids 0/r32/eax + 89/<- *Type-id 0/r32/eax # stream-write + (clear-stream _test-input-stream) + (write _test-input-stream "copy-to n, 3\n") + # var vars/ecx: (stack (addr var) 16) + 81 5/subop/subtract %esp 0xc0/imm32 + 68/push 0xc0/imm32/size + 68/push 0/imm32/top + 89/<- %ecx 4/r32/esp + (clear-stack %ecx) + # var v/edx: (handle var) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + # var s/eax: (handle array byte) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %eax 4/r32/esp + # v = new var("n") + (copy-array Heap "n" %eax) + (new-var Heap *eax *(eax+4) %edx) + # + (push %ecx *edx) + (push %ecx *(edx+4)) + (push %ecx 0) + # var out/eax: (handle stmt) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %eax 4/r32/esp + # convert + (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0) + # var out-addr/edx: (addr stmt) = lookup(*out) + (lookup *eax *(eax+4)) # => eax + 89/<- %edx 0/r32/eax + # out->tag + (check-ints-equal *edx 1 "F - test-parse-mu-stmt-with-comma/tag") # Stmt-tag is Stmt1 + # out->operation + (lookup *(edx+4) *(edx+8)) # Stmt1-operation Stmt1-operation => eax + (check-strings-equal %eax "copy-to" "F - test-parse-mu-stmt-with-comma/name") # Stmt1-operation + # out->inouts->value->name + # . eax = out->inouts + (lookup *(edx+0xc) *(edx+0x10)) # Stmt1-inouts Stmt1-inouts => eax + # . eax = out->inouts->value + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + # . eax = out->inouts->value->name + (lookup *eax *(eax+4)) # Var-name Var-name => eax + # . + (check-strings-equal %eax "n" "F - test-parse-mu-stmt-with-comma/inout:0") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +new-var: # ad: (addr allocation-descriptor), name: (handle array byte), out: (addr handle var) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + # ecx = out + 8b/-> *(ebp+0x14) 1/r32/ecx + # + (allocate *(ebp+8) *Var-size %ecx) + # var out-addr/eax: (addr var) + (lookup *ecx *(ecx+4)) # => eax + # out-addr->name = name + 8b/-> *(ebp+0xc) 1/r32/ecx + 89/<- *eax 1/r32/ecx # Var-name + 8b/-> *(ebp+0x10) 1/r32/ecx + 89/<- *(eax+4) 1/r32/ecx # Var-name +#? (write-buffered Stderr "var ") +#? (lookup *(ebp+0xc) *(ebp+0x10)) +#? (write-buffered Stderr %eax) +#? (write-buffered Stderr " at ") +#? 8b/-> *(ebp+0x14) 1/r32/ecx +#? (lookup *ecx *(ecx+4)) # => eax +#? (write-int32-hex-buffered Stderr %eax) +#? (write-buffered Stderr Newline) +#? (flush Stderr) +$new-var:end: + # . restore registers + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# WARNING: modifies name +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) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + # first strip out metadata + 8b/-> *(ebp+0xc) 1/r32/ecx + (next-token-from-slice *ecx *(ecx+4) 0x2f *(ebp+0xc)) + # if (!is-hex-int?(name)) abort + (is-hex-int? *(ebp+0xc)) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $new-literal-integer:abort/disp32 + # a little more error-checking + (check-mu-hex-int *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c)) + # out = new var(s) + (new-var-from-slice *(ebp+8) *(ebp+0xc) *(ebp+0x10)) + # var out-addr/ecx: (addr var) = lookup(*out) + 8b/-> *(ebp+0x10) 0/r32/eax + (lookup *eax *(eax+4)) # => eax + 89/<- %ecx 0/r32/eax + # out-addr->block-depth = *Curr-block-depth + 8b/-> *Curr-block-depth 0/r32/eax + 89/<- *(ecx+0x10) 0/r32/eax # Var-block-depth + # out-addr->type = new tree() + 8d/copy-address *(ecx+8) 0/r32/eax # Var-type + (allocate *(ebp+8) *Type-tree-size %eax) + (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + c7 0/subop/copy *eax 1/imm32/true # Type-tree-is-atom + # nothing else to do; default type is 'literal' +$new-literal-integer:end: + # . reclaim locals + 81 0/subop/add %esp 8/imm32 + # . restore registers + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$new-literal-integer:abort: + (write-buffered *(ebp+0x18) "fn ") + 8b/-> *(ebp+0x14) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x18) %eax) + (write-buffered *(ebp+0x18) ": variable '") + (write-slice-buffered *(ebp+0x18) *(ebp+0xc)) + (write-buffered *(ebp+0x18) "' cannot begin with a digit (or do you have a typo in a number?)\n") + (flush *(ebp+0x18)) + (stop *(ebp+0x1c) 1) + # never gets here + +# precondition: name is a valid hex integer; require a '0x' prefix +check-mu-hex-int: # name: (addr slice), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + # ecx = name + 8b/-> *(ebp+8) 1/r32/ecx + # var start/edx: (addr byte) = name->start + 8b/-> *ecx 2/r32/edx + # if (*start == '-') ++start + b8/copy-to-eax 0/imm32 + 8a/copy-byte *edx 0/r32/AL + 3d/compare-eax-and 0x2d/imm32/dash + { + 75/jump-if-!= break/disp8 + 42/increment-edx + } + # var end/ecx: (addr byte) = name->end + 8b/-> *(ecx+4) 1/r32/ecx + # var len/eax: int = name->end - name->start + 89/<- %eax 1/r32/ecx + 29/subtract-from %eax 2/r32/edx + # if (len <= 1) return + 3d/compare-eax-with 1/imm32 + 0f 8e/jump-if-<= $check-mu-hex-int:end/disp32 +$check-mu-hex-int:length->-1: + # if slice-starts-with?({start, end}, "0x") return + # . var tmp = {start, end} + 51/push-ecx + 52/push-edx + 89/<- %eax 4/r32/esp + # . + (slice-starts-with? %eax "0x") # => eax + # . reclaim tmp + 81 0/subop/add %esp 8/imm32 + # . + 3d/compare-eax-with 0/imm32/false + 75/jump-if-!= $check-mu-hex-int:end/disp8 +$check-mu-hex-int:abort: + # otherwise abort + (write-buffered *(ebp+0xc) "literal integers are always hex in Mu; start '") + (write-slice-buffered *(ebp+0xc) *(ebp+8)) + (write-buffered *(ebp+0xc) "' with a '0x' to be unambiguous, converting it to hexadecimal as necessary.\n") + (flush *(ebp+0xc)) + (stop *(ebp+0x10) 1) +$check-mu-hex-int:end: + # . restore registers + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +new-literal: # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + # var s/ecx: (handle array byte) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %ecx 4/r32/esp + # s = slice-to-string(name) + (slice-to-string Heap *(ebp+0xc) %ecx) + # allocate to out + (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10)) + # var out-addr/ecx: (addr var) = lookup(*out) + 8b/-> *(ebp+0x10) 1/r32/ecx + (lookup *ecx *(ecx+4)) # => eax + 89/<- %ecx 0/r32/eax + # out-addr->block-depth = *Curr-block-depth + 8b/-> *Curr-block-depth 0/r32/eax + 89/<- *(ecx+0x10) 0/r32/eax # Var-block-depth + # out-addr->type/eax = new type + 8d/copy-address *(ecx+8) 0/r32/eax # Var-type + (allocate *(ebp+8) *Type-tree-size %eax) + (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + # nothing else to do; default type is 'literal' + c7 0/subop/copy *eax 1/imm32/true # Type-tree-is-atom +$new-literal:end: + # . reclaim locals + 81 0/subop/add %esp 8/imm32 + # . restore registers + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +new-literal-string: # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + # var s/ecx: (handle array byte) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %ecx 4/r32/esp + # s = slice-to-string(name) + (slice-to-string Heap *(ebp+0xc) %ecx) + # allocate to out + (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10)) + # var out-addr/ecx: (addr var) = lookup(*out) + 8b/-> *(ebp+0x10) 1/r32/ecx + (lookup *ecx *(ecx+4)) # => eax + 89/<- %ecx 0/r32/eax + # out-addr->block-depth = *Curr-block-depth + 8b/-> *Curr-block-depth 0/r32/eax + 89/<- *(ecx+0x10) 0/r32/eax # Var-block-depth + # out-addr->type/eax = new type + 8d/copy-address *(ecx+8) 0/r32/eax # Var-type + (allocate *(ebp+8) *Type-tree-size %eax) + (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + # out-addr->type->value = literal-string + c7 0/subop/copy *(eax+4) 0x10/imm32/type-id-string-literal # Type-tree-value + # out-addr->type->is-atom? = true + c7 0/subop/copy *eax 1/imm32/true # Type-tree-is-atom +$new-literal-string:end: + # . reclaim locals + 81 0/subop/add %esp 8/imm32 + # . restore registers + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +new-var-from-slice: # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # var tmp/ecx: (handle array byte) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %ecx 4/r32/esp + # tmp = slice-to-string(name) + (slice-to-string Heap *(ebp+0xc) %ecx) + # out = new-var(tmp) + (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10)) +$new-var-from-slice:end: + # . reclaim locals + 81 0/subop/add %esp 8/imm32 + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +new-var-def: # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + # + (allocate *(ebp+8) *Stmt-size *(ebp+0x14)) + # var out-addr/eax: (addr stmt) = lookup(*out) + 8b/-> *(ebp+0x14) 0/r32/eax + (lookup *eax *(eax+4)) # => eax + # out-addr->tag = stmt + c7 0/subop/copy *eax 2/imm32/tag/var-on-stack # Stmt-tag + # result->var = var + 8b/-> *(ebp+0xc) 1/r32/ecx + 89/<- *(eax+4) 1/r32/ecx # Vardef-var + 8b/-> *(ebp+0x10) 1/r32/ecx + 89/<- *(eax+8) 1/r32/ecx # Vardef-var +$new-var-def:end: + # . restore registers + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +new-reg-var-def: # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + # eax = out + 8b/-> *(ebp+0x14) 0/r32/eax + # + (allocate *(ebp+8) *Stmt-size %eax) + # var out-addr/eax: (addr stmt) = lookup(*out) + (lookup *eax *(eax+4)) # => eax + # set tag + c7 0/subop/copy *eax 3/imm32/tag/var-in-register # Stmt-tag + # set output + 8d/copy-address *(eax+0x14) 0/r32/eax # Regvardef-outputs + (append-stmt-var Heap *(ebp+0xc) *(ebp+0x10) 0 0 0 %eax) +$new-reg-var-def:end: + # . restore registers + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +append-list: # ad: (addr allocation-descriptor), value: (handle _type), list: (handle list _type), out: (addr handle list _type) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 57/push-edi + # edi = out + 8b/-> *(ebp+0x1c) 7/r32/edi + # *out = new list + (allocate *(ebp+8) *List-size %edi) + # var out-addr/edi: (addr list _type) = lookup(*out) + (lookup *edi *(edi+4)) # => eax + 89/<- %edi 0/r32/eax + # out-addr->value = value + 8b/-> *(ebp+0xc) 0/r32/eax + 89/<- *edi 0/r32/eax # List-value + 8b/-> *(ebp+0x10) 0/r32/eax + 89/<- *(edi+4) 0/r32/eax # List-value + # if (list == null) return + 81 7/subop/compare *(ebp+0x14) 0/imm32 + 74/jump-if-= $append-list:end/disp8 + # otherwise append +$append-list:non-empty-list: + # var curr/eax: (addr list _type) = lookup(list) + (lookup *(ebp+0x14) *(ebp+0x18)) # => eax + # while (curr->next != null) curr = curr->next + { + 81 7/subop/compare *(eax+8) 0/imm32 # List-next + 74/jump-if-= break/disp8 + # curr = lookup(curr->next) + (lookup *(eax+8) *(eax+0xc)) # List-next, List-next => eax + # + eb/jump loop/disp8 + } + # edi = out + 8b/-> *(ebp+0x1c) 7/r32/edi + # curr->next = out + 8b/-> *edi 1/r32/ecx + 89/<- *(eax+8) 1/r32/ecx # List-next + 8b/-> *(edi+4) 1/r32/ecx + 89/<- *(eax+0xc) 1/r32/ecx # List-next + # out = list + 8b/-> *(ebp+0x14) 1/r32/ecx + 89/<- *edi 1/r32/ecx + 8b/-> *(ebp+0x18) 1/r32/ecx + 89/<- *(edi+4) 1/r32/ecx +$append-list:end: + # . restore registers + 5f/pop-to-edi + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +append-stmt-var: # ad: (addr allocation-descriptor), v: (handle var), vars: (handle stmt-var), is-deref?: boolean, out: (addr handle stmt-var) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 57/push-edi + # edi = out + 8b/-> *(ebp+0x20) 7/r32/edi + # out = new stmt-var + (allocate *(ebp+8) *Stmt-var-size %edi) + # var out-addr/ecx: (addr stmt-var) = lookup(*out) + (lookup *edi *(edi+4)) # => eax + 89/<- %ecx 0/r32/eax + # out-addr->value = v + 8b/-> *(ebp+0xc) 0/r32/eax + 89/<- *ecx 0/r32/eax # Stmt-var-value + 8b/-> *(ebp+0x10) 0/r32/eax + 89/<- *(ecx+4) 0/r32/eax # Stmt-var-value + # out-addr->is-deref? = is-deref? + 8b/-> *(ebp+0x1c) 0/r32/eax + 89/<- *(ecx+0x10) 0/r32/eax # Stmt-var-is-deref + # if (vars == null) return result + 81 7/subop/compare *(ebp+0x14) 0/imm32/null + 74/jump-if-= $append-stmt-var:end/disp8 + # otherwise append + # var curr/eax: (addr stmt-var) = lookup(vars) + (lookup *(ebp+0x14) *(ebp+0x18)) # => eax + # while (curr->next != null) curr = curr->next + { + 81 7/subop/compare *(eax+8) 0/imm32 # Stmt-var-next + 74/jump-if-= break/disp8 + # curr = lookup(curr->next) + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next, Stmt-var-next => eax + # + eb/jump loop/disp8 + } + # curr->next = out + 8b/-> *edi 1/r32/ecx + 89/<- *(eax+8) 1/r32/ecx # Stmt-var-next + 8b/-> *(edi+4) 1/r32/ecx + 89/<- *(eax+0xc) 1/r32/ecx # Stmt-var-next + # out = vars + 8b/-> *(ebp+0x14) 1/r32/ecx + 89/<- *edi 1/r32/ecx + 8b/-> *(ebp+0x18) 1/r32/ecx + 89/<- *(edi+4) 1/r32/ecx +$append-stmt-var:end: + # . restore registers + 5f/pop-to-edi + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +append-to-block: # ad: (addr allocation-descriptor), block: (addr block), x: (handle stmt) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 56/push-esi + # esi = block + 8b/-> *(ebp+0xc) 6/r32/esi + # block->stmts = append(x, block->stmts) + 8d/copy-address *(esi+4) 0/r32/eax # Block-stmts + (append-list *(ebp+8) *(ebp+0x10) *(ebp+0x14) *(esi+4) *(esi+8) %eax) # ad, x, x, Block-stmts, Block-stmts +$append-to-block:end: + # . restore registers + 5e/pop-to-esi + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +## Parsing types +# We need to create metadata on user-defined types, and we need to use this +# metadata as we parse instructions. +# However, we also want to allow types to be used before their definitions. +# This means we can't ever assume any type data structures exist. + +lookup-or-create-constant: # container: (addr stmt-var), field-name: (addr slice), out: (addr handle var) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 56/push-esi + # var container-type/esi: type-id + (container-type *(ebp+8)) # => eax + 89/<- %esi 0/r32/eax + # var tmp/eax: (handle typeinfo) = find-or-create-typeinfo(container-type) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %eax 4/r32/esp + (find-or-create-typeinfo %esi %eax) + # var tmp-addr/eax: (addr typeinfo) = lookup(tmp) + (lookup *eax *(eax+4)) # => eax + # result = find-or-create-typeinfo-output-var(typeinfo, field-name) +#? (write-buffered Stderr "constant: ") +#? (write-slice-buffered Stderr *(ebp+0xc)) +#? (write-buffered Stderr Newline) +#? (flush Stderr) + (find-or-create-typeinfo-output-var %eax *(ebp+0xc) *(ebp+0x10)) +#? 8b/-> *(ebp+0x10) 0/r32/eax +#? (write-buffered Stderr "@") +#? (lookup *eax *(eax+4)) +#? (write-int32-hex-buffered Stderr %eax) +#? (lookup *eax *(eax+4)) +#? (write-buffered Stderr %eax) +#? (write-buffered Stderr Newline) +#? (flush Stderr) +#? (write-buffered Stderr "offset: ") +#? 8b/-> *(eax+0x14) 0/r32/eax +#? (write-int32-hex-buffered Stderr %eax) +#? (write-buffered Stderr Newline) +#? (flush Stderr) +$lookup-or-create-constant:end: + # . reclaim locals + 81 0/subop/add %esp 8/imm32 + # . restore registers + 5e/pop-to-esi + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# if addr var: +# container->var->type->right->left->value +# otherwise +# container->var->type->value +container-type: # container: (addr stmt-var) -> result/eax: type-id + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # + 8b/-> *(ebp+8) 0/r32/eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + { + 81 7/subop/compare *(eax+8) 0/imm32 # Type-tree-right + 74/jump-if-= break/disp8 + (lookup *(eax+0xc) *(eax+0x10)) # Type-tree-right Type-tree-right => eax + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } + 8b/-> *(eax+4) 0/r32/eax # Type-tree-value +$container-type:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +is-container?: # t: type-id -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # + 8b/-> *(ebp+8) 0/r32/eax + c1/shift 4/subop/left %eax 2/imm8 + 3b/compare 0/r32/eax *Primitive-type-ids + 0f 9d/set-if->= %al + 81 4/subop/and %eax 0xff/imm32 +$is-container?:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +find-or-create-typeinfo: # t: type-id, out: (addr handle typeinfo) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 57/push-edi + # edi = out + 8b/-> *(ebp+0xc) 7/r32/edi + # var fields/ecx: (handle table (handle array byte) (handle typeinfo-entry)) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %ecx 4/r32/esp + # find-typeinfo(t, out) + (find-typeinfo *(ebp+8) %edi) + { + # if (*out != 0) break + 81 7/subop/compare *edi 0/imm32 + 0f 85/jump-if-!= break/disp32 +$find-or-create-typeinfo:create: + # *out = allocate + (allocate Heap *Typeinfo-size %edi) + # var tmp/eax: (addr typeinfo) = lookup(*out) + (lookup *edi *(edi+4)) # => eax +#? (write-buffered Stderr "created typeinfo at ") +#? (write-int32-hex-buffered Stderr %eax) +#? (write-buffered Stderr " for type-id ") +#? (write-int32-hex-buffered Stderr *(ebp+8)) +#? (write-buffered Stderr Newline) +#? (flush Stderr) + # tmp->id = t + 8b/-> *(ebp+8) 2/r32/edx + 89/<- *eax 2/r32/edx # Typeinfo-id + # tmp->fields = new table + # . fields = new table + (new-stream Heap 0x40 *Typeinfo-fields-row-size %ecx) + # . tmp->fields = fields + 8b/-> *ecx 2/r32/edx + 89/<- *(eax+4) 2/r32/edx # Typeinfo-fields + 8b/-> *(ecx+4) 2/r32/edx + 89/<- *(eax+8) 2/r32/edx # Typeinfo-fields + # tmp->next = Program->types + 8b/-> *_Program-types 1/r32/ecx + 89/<- *(eax+0x10) 1/r32/ecx # Typeinfo-next + 8b/-> *_Program-types->payload 1/r32/ecx + 89/<- *(eax+0x14) 1/r32/ecx # Typeinfo-next + # Program->types = out + 8b/-> *edi 1/r32/ecx + 89/<- *_Program-types 1/r32/ecx + 8b/-> *(edi+4) 1/r32/ecx + 89/<- *_Program-types->payload 1/r32/ecx + } +$find-or-create-typeinfo:end: + # . reclaim locals + 81 0/subop/add %esp 8/imm32 + # . restore registers + 5f/pop-to-edi + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +find-typeinfo: # t: type-id, out: (addr handle typeinfo) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 57/push-edi + # ecx = t + 8b/-> *(ebp+8) 1/r32/ecx + # edi = out + 8b/-> *(ebp+0xc) 7/r32/edi + # *out = Program->types + 8b/-> *_Program-types 0/r32/eax + 89/<- *edi 0/r32/eax + 8b/-> *_Program-types->payload 0/r32/eax + 89/<- *(edi+4) 0/r32/eax + { +$find-typeinfo:loop: + # if (*out == 0) break + 81 7/subop/compare *edi 0/imm32 + 74/jump-if-= break/disp8 +$find-typeinfo:check: + # var tmp/eax: (addr typeinfo) = lookup(*out) + (lookup *edi *(edi+4)) # => eax + # if (tmp->id == t) break + 39/compare *eax 1/r32/ecx # Typeinfo-id + 74/jump-if-= break/disp8 +$find-typeinfo:continue: + # *out = tmp->next + 8b/-> *(eax+0x10) 2/r32/edx # Typeinfo-next + 89/<- *edi 2/r32/edx + 8b/-> *(eax+0x14) 2/r32/edx # Typeinfo-next + 89/<- *(edi+4) 2/r32/edx + # + eb/jump loop/disp8 + } +$find-typeinfo:end: + # . restore registers + 5f/pop-to-edi + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +find-or-create-typeinfo-output-var: # T: (addr typeinfo), f: (addr slice), out: (addr handle var) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 52/push-edx + 57/push-edi + # var dest/edi: (handle typeinfo-entry) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edi 4/r32/esp + # find-or-create-typeinfo-fields(T, f, dest) + (find-or-create-typeinfo-fields *(ebp+8) *(ebp+0xc) %edi) + # var dest-addr/edi: (addr typeinfo-entry) = lookup(dest) + (lookup *edi *(edi+4)) # => eax + 89/<- %edi 0/r32/eax + # if dest-addr->output-var doesn't exist, create it + { + 81 7/subop/compare *(edi+0xc) 0/imm32 # Typeinfo-entry-output-var + 0f 85/jump-if-!= break/disp32 + # dest-addr->output-var = new var(dummy name, type, -1 offset) + # . var name/eax: (handle array byte) = "field" + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %eax 4/r32/esp + (slice-to-string Heap *(ebp+0xc) %eax) + # . new var + 8d/copy-address *(edi+0xc) 2/r32/edx + (new-var Heap *eax *(eax+4) %edx) + # . reclaim name + 81 0/subop/add %esp 8/imm32 + # var result/edx: (addr var) = lookup(dest-addr->output-var) + (lookup *(edi+0xc) *(edi+0x10)) # => eax + 89/<- %edx 0/r32/eax + # result->type = new constant type + 8d/copy-address *(edx+8) 0/r32/eax # Var-type + (allocate Heap *Type-tree-size %eax) + (lookup *(edx+8) *(edx+0xc)) # => eax + c7 0/subop/copy *eax 1/imm32/true # Type-tree-is-atom + c7 0/subop/copy *(eax+4) 6/imm32/constant # Type-tree-value + c7 0/subop/copy *(eax+8) 0/imm32 # Type-tree-left + c7 0/subop/copy *(eax+0xc) 0/imm32 # Type-tree-right + c7 0/subop/copy *(eax+0x10) 0/imm32 # Type-tree-right + # result->offset isn't filled out yet + c7 0/subop/copy *(edx+0x14) -1/imm32/uninitialized # Var-offset + } + # out = dest-addr->output-var + 8b/-> *(ebp+0x10) 2/r32/edx + 8b/-> *(edi+0xc) 0/r32/eax # Typeinfo-entry-output-var + 89/<- *edx 0/r32/eax + 8b/-> *(edi+0x10) 0/r32/eax # Typeinfo-entry-output-var + 89/<- *(edx+4) 0/r32/eax +$find-or-create-typeinfo-output-var:end: + # . reclaim locals + 81 0/subop/add %esp 8/imm32 + # . restore registers + 5f/pop-to-edi + 5a/pop-to-edx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +find-or-create-typeinfo-fields: # T: (addr typeinfo), f: (addr slice), out: (addr handle typeinfo-entry) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 56/push-esi + 57/push-edi + # eax = lookup(T->fields) + 8b/-> *(ebp+8) 0/r32/eax + (lookup *(eax+4) *(eax+8)) # Typeinfo-fields Typeinfo-fields => eax + # edi = out + 8b/-> *(ebp+0x10) 7/r32/edi + # var src/esi: (addr handle typeinfo-entry) = get-or-insert-slice(T->fields, f) + (get-or-insert-slice %eax *(ebp+0xc) *Typeinfo-fields-row-size Heap) # => eax + 89/<- %esi 0/r32/eax + # if src doesn't exist, allocate it + { + 81 7/subop/compare *esi 0/imm32 + 75/jump-if-!= break/disp8 + (allocate Heap *Typeinfo-entry-size %esi) +#? (write-buffered Stderr "handle at ") +#? (write-int32-hex-buffered Stderr %esi) +#? (write-buffered Stderr ": ") +#? (write-int32-hex-buffered Stderr *esi) +#? (write-buffered Stderr " ") +#? (write-int32-hex-buffered Stderr *(esi+4)) +#? (write-buffered Stderr Newline) +#? (flush Stderr) +#? (lookup *esi *(esi+4)) +#? (write-buffered Stderr "created typeinfo fields at ") +#? (write-int32-hex-buffered Stderr %esi) +#? (write-buffered Stderr " for ") +#? (write-int32-hex-buffered Stderr *(ebp+8)) +#? (write-buffered Stderr Newline) +#? (flush Stderr) + } + # *out = src + # . *edi = *src + 8b/-> *esi 0/r32/eax + 89/<- *edi 0/r32/eax + 8b/-> *(esi+4) 0/r32/eax + 89/<- *(edi+4) 0/r32/eax +$find-or-create-typeinfo-fields:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +populate-mu-type: # in: (addr stream byte), t: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor) + # pseudocode: + # var line: (stream byte 512) + # curr-index = 0 + # while true + # clear-stream(line) + # read-line-buffered(in, line) + # if line->write == 0 + # abort + # word-slice = next-mu-token(line) + # if slice-empty?(word-slice) # end of line + # continue + # if slice-equal?(word-slice, "}") + # break + # var v: (handle var) = parse-var-with-type(word-slice, line) + # var r: (handle typeinfo-fields) = find-or-create-typeinfo-fields(t, word-slice/v->name) + # TODO: ensure that r->first is null + # r->index = curr-index + # curr-index++ + # r->input-var = v + # if r->output-var == 0 + # r->output-var = new literal + # TODO: ensure nothing else in line + # t->total-size-in-bytes = -2 (not yet initialized) + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # var curr-index: int at *(ebp-4) + 68/push 0/imm32 + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + 57/push-edi + # edi = t + 8b/-> *(ebp+0xc) 7/r32/edi + # var line/ecx: (stream byte 512) + 81 5/subop/subtract %esp 0x200/imm32 + 68/push 0x200/imm32/size + 68/push 0/imm32/read + 68/push 0/imm32/write + 89/<- %ecx 4/r32/esp + # var word-slice/edx: slice + 68/push 0/imm32/end + 68/push 0/imm32/start + 89/<- %edx 4/r32/esp + # var v/esi: (handle var) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %esi 4/r32/esp + # var r/ebx: (handle typeinfo-entry) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %ebx 4/r32/esp + { +$populate-mu-type:line-loop: + (clear-stream %ecx) + (read-line-buffered *(ebp+8) %ecx) + # if (line->write == 0) abort + 81 7/subop/compare *ecx 0/imm32 + 0f 84/jump-if-= $populate-mu-type:error1/disp32 +#? # dump line {{{ +#? (write 2 "parse-mu: ^") +#? (write-stream 2 %ecx) +#? (write 2 "$\n") +#? (rewind-stream %ecx) +#? # }}} + (next-mu-token %ecx %edx) + # if slice-empty?(word-slice) continue + (slice-empty? %edx) # => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= loop/disp32 + # if slice-equal?(word-slice, "}") break + (slice-equal? %edx "}") + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= break/disp32 +$populate-mu-type:parse-element: + # v = parse-var-with-type(word-slice, first-line) + # must do this first to strip the trailing ':' from word-slice before + # using it in find-or-create-typeinfo-fields below + # TODO: clean up that mutation in parse-var-with-type + (type-name *edi) # Typeinfo-id => eax + (parse-var-with-type %edx %ecx %esi %eax *(ebp+0x10) *(ebp+0x14)) + # if v is an addr, abort + (lookup *esi *(esi+4)) # => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + (is-mu-addr-type? %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-type:error2/disp32 + # if v is an array, abort (we could support it, but initialization gets complex) + (lookup *esi *(esi+4)) # => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + (is-mu-array-type? %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-type:error3/disp32 + # if v is a byte, abort + (lookup *esi *(esi+4)) # => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + (is-simple-mu-type? %eax 8) # byte => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-type:error4/disp32 + # if v is a slice, abort + (lookup *esi *(esi+4)) # => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + (is-simple-mu-type? %eax 0xc) # slice => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-type:error5/disp32 + # if v is a stream, abort (we could support it, but initialization gets even more complex) + (lookup *esi *(esi+4)) # => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + (is-mu-stream-type? %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $populate-mu-type:error6/disp32 + # var tmp/ecx + 51/push-ecx +$populate-mu-type:create-typeinfo-fields: + # var r/ebx: (handle typeinfo-entry) + (find-or-create-typeinfo-fields %edi %edx %ebx) + # r->index = curr-index + (lookup *ebx *(ebx+4)) # => eax + 8b/-> *(ebp-4) 1/r32/ecx +#? (write-buffered Stderr "saving index ") +#? (write-int32-hex-buffered Stderr %ecx) +#? (write-buffered Stderr " at ") +#? (write-int32-hex-buffered Stderr %edi) +#? (write-buffered Stderr Newline) +#? (flush Stderr) + 89/<- *(eax+8) 1/r32/ecx # Typeinfo-entry-index + # ++curr-index + ff 0/subop/increment *(ebp-4) +$populate-mu-type:set-input-type: + # r->input-var = v + 8b/-> *esi 1/r32/ecx + 89/<- *eax 1/r32/ecx # Typeinfo-entry-input-var + 8b/-> *(esi+4) 1/r32/ecx + 89/<- *(eax+4) 1/r32/ecx # Typeinfo-entry-input-var + # restore line + 59/pop-to-ecx + { +$populate-mu-type:create-output-type: + # if (r->output-var == 0) create a new var with some placeholder data + 81 7/subop/compare *(eax+0xc) 0/imm32 # Typeinfo-entry-output-var + 75/jump-if-!= break/disp8 + 8d/copy-address *(eax+0xc) 0/r32/eax # Typeinfo-entry-output-var + (new-literal Heap %edx %eax) + } + e9/jump loop/disp32 + } +$populate-mu-type:invalidate-total-size-in-bytes: + # Offsets and total size may not be accurate here since we may not yet + # have encountered the element types. + # We'll recompute them separately after parsing the entire program. + c7 0/subop/copy *(edi+0xc) -2/imm32/uninitialized # Typeinfo-total-size-in-bytes +$populate-mu-type:end: + # . reclaim locals + 81 0/subop/add %esp 0x224/imm32 + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # reclaim curr-index + 81 0/subop/add %esp 4/imm32 + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$populate-mu-type:error1: + # error("incomplete type definition '" t->name "'\n") + (write-buffered *(ebp+0x10) "incomplete type definition '") + (type-name *edi) # Typeinfo-id => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$populate-mu-type:error2: + (write-buffered *(ebp+0x10) "type ") + (type-name *edi) # Typeinfo-id => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": 'addr' elements not allowed\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$populate-mu-type:error3: + (write-buffered *(ebp+0x10) "type ") + (type-name *edi) # Typeinfo-id => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": 'array' elements not allowed for now\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$populate-mu-type:error4: + (write-buffered *(ebp+0x10) "type ") + (type-name *edi) # Typeinfo-id => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": 'byte' elements not allowed\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$populate-mu-type:error5: + (write-buffered *(ebp+0x10) "type ") + (type-name *edi) # Typeinfo-id => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": 'slice' elements not allowed\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$populate-mu-type:error6: + (write-buffered *(ebp+0x10) "type ") + (type-name *edi) # Typeinfo-id => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": 'stream' elements not allowed for now\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +type-name: # index: int -> result/eax: (addr array byte) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # + (index Type-id *(ebp+8)) +$type-name:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +index: # arr: (addr stream (handle array byte)), index: int -> result/eax: (addr array byte) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 56/push-esi + # TODO: bounds-check index + # esi = arr + 8b/-> *(ebp+8) 6/r32/esi + # eax = index + 8b/-> *(ebp+0xc) 0/r32/eax + # eax = *(arr + 12 + index) + 8b/-> *(esi+eax<<2+0xc) 0/r32/eax +$index:end: + # . restore registers + 5e/pop-to-esi + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +####################################################### +# Compute type sizes +####################################################### + +# Compute the sizes of all user-defined types. +# We'll need the sizes of their elements, which may be other user-defined +# types, which we will compute as needed. + +# Initially, all user-defined types have their sizes set to -2 (invalid) +populate-mu-type-sizes: # err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp +$populate-mu-type-sizes:total-sizes: + # var curr/eax: (addr typeinfo) = lookup(Program->types) + (lookup *_Program-types *_Program-types->payload) # => eax + { + # if (curr == null) break + 3d/compare-eax-and 0/imm32/null + 74/jump-if-= break/disp8 + (populate-mu-type-sizes-in-type %eax *(ebp+8) *(ebp+0xc)) + # curr = lookup(curr->next) + (lookup *(eax+0x10) *(eax+0x14)) # Typeinfo-next Typeinfo-next => eax + eb/jump loop/disp8 + } +$populate-mu-type-sizes:offsets: + # curr = *Program->types + (lookup *_Program-types *_Program-types->payload) # => eax + { + # if (curr == null) break + 3d/compare-eax-and 0/imm32/null + 74/jump-if-= break/disp8 + (populate-mu-type-offsets %eax *(ebp+8) *(ebp+0xc)) + # curr = curr->next + (lookup *(eax+0x10) *(eax+0x14)) # Typeinfo-next Typeinfo-next => eax + eb/jump loop/disp8 + } +$populate-mu-type-sizes:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# compute sizes of all fields, recursing as necessary +# sum up all their sizes to arrive at total size +# fields may be out of order, but that doesn't affect the answer +populate-mu-type-sizes-in-type: # T: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 56/push-esi + 57/push-edi + # esi = T + 8b/-> *(ebp+8) 6/r32/esi + # if T is already computed, return + 81 7/subop/compare *(esi+0xc) 0/imm32 # Typeinfo-total-size-in-bytes + 0f 8d/jump-if->= $populate-mu-type-sizes-in-type:end/disp32 + # if T is being computed, abort + 81 7/subop/compare *(esi+0xc) -1/imm32/being-computed # Typeinfo-total-size-in-bytes + 0f 84/jump-if-= $populate-mu-type-sizes-in-type:abort/disp32 + # tag T (-2 to -1) to avoid infinite recursion + c7 0/subop/copy *(esi+0xc) -1/imm32/being-computed # Typeinfo-total-size-in-bytes + # var total-size/edi: int = 0 + bf/copy-to-edi 0/imm32 + # - for every field, if it's a user-defined type, compute its size + # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields) + (lookup *(esi+4) *(esi+8)) # Typeinfo-fields Typeinfo-fields => eax + 89/<- %ecx 0/r32/eax + # var table-size/edx: int = table->write + 8b/-> *ecx 2/r32/edx # stream-write + # var curr/ecx: (addr table_row) = table->data + 8d/copy-address *(ecx+0xc) 1/r32/ecx + # var max/edx: (addr table_row) = table->data + table->write + 8d/copy-address *(ecx+edx) 2/r32/edx + { +$populate-mu-type-sizes-in-type:loop: + # if (curr >= max) break + 39/compare %ecx 2/r32/edx + 73/jump-if-addr>= break/disp8 + # var t/eax: (addr typeinfo-entry) = lookup(curr->value) + (lookup *(ecx+8) *(ecx+0xc)) # => eax + # if (t->input-var == 0) silently ignore it; we'll emit a nice error message while type-checking + 81 7/subop/compare *eax 0/imm32 # Typeinfo-entry-input-var + 74/jump-if-= $populate-mu-type-sizes-in-type:end/disp8 + # compute size of t->input-var + (lookup *eax *(eax+4)) # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax + (compute-size-of-var %eax *(ebp+0xc) *(ebp+0x10)) # => eax + # result += eax + 01/add-to %edi 0/r32/eax + # curr += row-size + 81 0/subop/add %ecx 0x10/imm32 # Typeinfo-fields-row-size + # + eb/jump loop/disp8 + } + # - save result + 89/<- *(esi+0xc) 7/r32/edi # Typeinfo-total-size-in-bytes +$populate-mu-type-sizes-in-type:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$populate-mu-type-sizes-in-type:abort: + (write-buffered *(ebp+0xc) "cycle in type definitions\n") + (flush *(ebp+0xc)) + (stop *(ebp+0x10) 1) + # never gets here + +# Analogous to size-of, except we need to compute what size-of can just read +# off the right data structures. +compute-size-of-var: # in: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . push registers + 51/push-ecx + # var t/ecx: (addr type-tree) = lookup(v->type) + 8b/-> *(ebp+8) 1/r32/ecx + (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + 89/<- %ecx 0/r32/eax + # if (t->is-atom == false) t = lookup(t->left) + { + 81 7/subop/compare *ecx 0/imm32/false # Type-tree-is-atom + 75/jump-if-!= break/disp8 + (lookup *(ecx+4) *(ecx+8)) # Type-tree-left Type-tree-left => eax + 89/<- %ecx 0/r32/eax + } + # TODO: ensure t is an atom + (compute-size-of-type-id *(ecx+4) *(ebp+0xc) *(ebp+0x10)) # Type-tree-value => eax +$compute-size-of-var:end: + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +compute-size-of-type-id: # t: type-id, err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # var out/ecx: (handle typeinfo) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %ecx 4/r32/esp + # eax = t + 8b/-> *(ebp+8) 0/r32/eax + # if t is a literal, return 0 + 3d/compare-eax-and 0/imm32/literal + 0f 84/jump-if-= $compute-size-of-type-id:end/disp32 # eax changes type from type-id to int + # if t is a byte, return 4 (because we don't really support non-multiples of 4) + 3d/compare-eax-and 8/imm32/byte + { + 75/jump-if-!= break/disp8 + b8/copy-to-eax 4/imm32 + eb/jump $compute-size-of-type-id:end/disp8 + } + # if t is a handle, return 8 + 3d/compare-eax-and 4/imm32/handle + { + 75/jump-if-!= break/disp8 + b8/copy-to-eax 8/imm32 + eb/jump $compute-size-of-type-id:end/disp8 # eax changes type from type-id to int + } + # if t is a slice, return 8 + 3d/compare-eax-and 0xc/imm32/slice + { + 75/jump-if-!= break/disp8 + b8/copy-to-eax 8/imm32 + eb/jump $compute-size-of-type-id:end/disp8 # eax changes type from type-id to int + } + # if t is a user-defined type, compute its size + # TODO: support non-atom type + (find-typeinfo %eax %ecx) + { + 81 7/subop/compare *ecx 0/imm32 + 74/jump-if-= break/disp8 +$compute-size-of-type-id:user-defined: + (lookup *ecx *(ecx+4)) # => eax + (populate-mu-type-sizes-in-type %eax *(ebp+0xc) *(ebp+0x10)) + 8b/-> *(eax+0xc) 0/r32/eax # Typeinfo-total-size-in-bytes + eb/jump $compute-size-of-type-id:end/disp8 + } + # otherwise return the word size + b8/copy-to-eax 4/imm32 +$compute-size-of-type-id:end: + # . reclaim locals + 81 0/subop/add %esp 8/imm32 + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# at this point we have total sizes for all user-defined types +# compute offsets for each element +# complication: fields may be out of order +populate-mu-type-offsets: # in: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + 57/push-edi +#? (dump-typeinfos "aaa\n") + # var curr-offset/edi: int = 0 + bf/copy-to-edi 0/imm32 + # var table/ecx: (addr table string_key (handle typeinfo-entry)) = lookup(in->fields) + 8b/-> *(ebp+8) 1/r32/ecx + (lookup *(ecx+4) *(ecx+8)) # Typeinfo-fields Typeinfo-fields => eax + 89/<- %ecx 0/r32/eax + # var num-elems/edx: int = table->write / Typeinfo-fields-row-size + 8b/-> *ecx 2/r32/edx # stream-write + c1 5/subop/shift-right-logical %edx 4/imm8 + # var i/ebx: int = 0 + bb/copy-to-ebx 0/imm32 + { +$populate-mu-type-offsets:loop: + 39/compare %ebx 2/r32/edx + 0f 8d/jump-if->= break/disp32 +#? (write-buffered Stderr "looking up index ") +#? (write-int32-hex-buffered Stderr %ebx) +#? (write-buffered Stderr " in ") +#? (write-int32-hex-buffered Stderr *(ebp+8)) +#? (write-buffered Stderr Newline) +#? (flush Stderr) + # var v/esi: (addr typeinfo-entry) + (locate-typeinfo-entry-with-index %ecx %ebx *(ebp+0xc) *(ebp+0x10)) # => eax + 89/<- %esi 0/r32/eax + # if v is null, silently move on; we'll emit a nice error message while type-checking + 81 7/subop/compare %esi 0/imm32 # Typeinfo-entry-input-var + 74/jump-if-= $populate-mu-type-offsets:end/disp8 + # if (v->input-var == 0) silently ignore v; we'll emit a nice error message while type-checking + 81 7/subop/compare *esi 0/imm32 # Typeinfo-entry-input-var + 74/jump-if-= $populate-mu-type-offsets:end/disp8 + # v->output-var->offset = curr-offset + # . eax: (addr var) + (lookup *(esi+0xc) *(esi+0x10)) # Typeinfo-entry-output-var Typeinfo-entry-output-var => eax + 89/<- *(eax+0x14) 7/r32/edi # Var-offset + # curr-offset += size-of(v->input-var) + (lookup *esi *(esi+4)) # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax + (size-of %eax) # => eax + 01/add-to %edi 0/r32/eax + # ++i + 43/increment-ebx + e9/jump loop/disp32 + } +$populate-mu-type-offsets:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +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) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + 57/push-edi + # esi = table + 8b/-> *(ebp+8) 6/r32/esi + # var curr/ecx: (addr row (handle array byte) (handle typeinfo-entry)) = table->data + 8d/copy-address *(esi+0xc) 1/r32/ecx + # var max/edx: (addr byte) = &table->data[table->write] + 8b/-> *esi 2/r32/edx + 8d/copy-address *(ecx+edx) 2/r32/edx + { +$locate-typeinfo-entry-with-index:loop: + 39/compare %ecx 2/r32/edx + 73/jump-if-addr>= break/disp8 + # var v/eax: (addr typeinfo-entry) + (lookup *(ecx+8) *(ecx+0xc)) # => eax + # if (v->index == idx) return v + 8b/-> *(eax+8) 3/r32/ebx # Typeinfo-entry-index +#? (write-buffered Stderr "comparing ") +#? (write-int32-hex-buffered Stderr %ebx) +#? (write-buffered Stderr " and ") +#? (write-int32-hex-buffered Stderr *(ebp+0xc)) +#? (write-buffered Stderr Newline) +#? (flush Stderr) + 39/compare *(ebp+0xc) 3/r32/ebx + 74/jump-if-= $locate-typeinfo-entry-with-index:end/disp8 + # curr += Typeinfo-entry-size + 81 0/subop/add %ecx 0x10/imm32 # Typeinfo-entry-size + # + eb/jump loop/disp8 + } + # return 0 + b8/copy-to-eax 0/imm32 +$locate-typeinfo-entry-with-index:end: +#? (write-buffered Stderr "returning ") +#? (write-int32-hex-buffered Stderr %eax) +#? (write-buffered Stderr Newline) +#? (flush Stderr) + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +dump-typeinfos: # hdr: (addr array byte) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + # + (write-buffered Stderr *(ebp+8)) + (flush Stderr) + # var curr/eax: (addr typeinfo) = lookup(Program->types) + (lookup *_Program-types *_Program-types->payload) # => eax + { + # if (curr == null) break + 3d/compare-eax-and 0/imm32 + 74/jump-if-= break/disp8 + (write-buffered Stderr "---\n") + (flush Stderr) + (dump-typeinfo %eax) + # curr = lookup(curr->next) + (lookup *(eax+0x10) *(eax+0x14)) # Typeinfo-next Typeinfo-next => eax + eb/jump loop/disp8 + } +$dump-typeinfos:end: + # . restore registers + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +dump-typeinfo: # in: (addr typeinfo) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + 57/push-edi + # esi = in + 8b/-> *(ebp+8) 6/r32/esi + # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields) + (lookup *(esi+4) *(esi+8)) # Typeinfo-fields Typeinfo-fields => eax + 89/<- %ecx 0/r32/eax + (write-buffered Stderr "id:") + (write-int32-hex-buffered Stderr *esi) + (write-buffered Stderr "\n") + (write-buffered Stderr "fields @ ") + (write-int32-hex-buffered Stderr %ecx) + (write-buffered Stderr Newline) + (flush Stderr) + (write-buffered Stderr " write: ") + (write-int32-hex-buffered Stderr *ecx) + (write-buffered Stderr Newline) + (flush Stderr) + (write-buffered Stderr " read: ") + (write-int32-hex-buffered Stderr *(ecx+4)) + (write-buffered Stderr Newline) + (flush Stderr) + (write-buffered Stderr " size: ") + (write-int32-hex-buffered Stderr *(ecx+8)) + (write-buffered Stderr Newline) + (flush Stderr) + # var table-size/edx: int = table->write + 8b/-> *ecx 2/r32/edx # stream-write + # var curr/ecx: (addr table_row) = table->data + 8d/copy-address *(ecx+0xc) 1/r32/ecx + # var max/edx: (addr table_row) = table->data + table->write + 8d/copy-address *(ecx+edx) 2/r32/edx + { +$dump-typeinfo:loop: + # if (curr >= max) break + 39/compare %ecx 2/r32/edx + 0f 83/jump-if-addr>= break/disp32 + (write-buffered Stderr " row:\n") + (write-buffered Stderr " key: ") + (write-int32-hex-buffered Stderr *ecx) + (write-buffered Stderr ",") + (write-int32-hex-buffered Stderr *(ecx+4)) + (write-buffered Stderr " = '") + (lookup *ecx *(ecx+4)) + (write-buffered Stderr %eax) + (write-buffered Stderr "' @ ") + (write-int32-hex-buffered Stderr %eax) + (write-buffered Stderr Newline) + (flush Stderr) + (write-buffered Stderr " value: ") + (write-int32-hex-buffered Stderr *(ecx+8)) + (write-buffered Stderr ",") + (write-int32-hex-buffered Stderr *(ecx+0xc)) + (write-buffered Stderr " = typeinfo-entry@") + (lookup *(ecx+8) *(ecx+0xc)) + (write-int32-hex-buffered Stderr %eax) + (write-buffered Stderr Newline) + (flush Stderr) + (write-buffered Stderr " input var@") + (dump-var 5 %eax) + (lookup *(ecx+8) *(ecx+0xc)) + (write-buffered Stderr " index: ") + (write-int32-hex-buffered Stderr *(eax+8)) + (write-buffered Stderr Newline) + (flush Stderr) + (write-buffered Stderr " output var@") + 8d/copy-address *(eax+0xc) 0/r32/eax # Typeinfo-entry-output-var + (dump-var 5 %eax) + (flush Stderr) + # curr += row-size + 81 0/subop/add %ecx 0x10/imm32 # Typeinfo-fields-row-size + # + e9/jump loop/disp32 + } +$dump-typeinfo:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +dump-var: # indent: int, v: (addr handle var) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 53/push-ebx + # eax = v + 8b/-> *(ebp+0xc) 0/r32/eax + # + (write-int32-hex-buffered Stderr *eax) + (write-buffered Stderr ",") + (write-int32-hex-buffered Stderr *(eax+4)) + (write-buffered Stderr "->") + (lookup *eax *(eax+4)) + (write-int32-hex-buffered Stderr %eax) + (write-buffered Stderr Newline) + (flush Stderr) + { + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= break/disp32 + (emit-indent Stderr *(ebp+8)) + (write-buffered Stderr "name: ") + 89/<- %ebx 0/r32/eax + (write-int32-hex-buffered Stderr *ebx) # Var-name + (write-buffered Stderr ",") + (write-int32-hex-buffered Stderr *(ebx+4)) # Var-name + (write-buffered Stderr "->") + (lookup *ebx *(ebx+4)) # Var-name + (write-int32-hex-buffered Stderr %eax) + { + 3d/compare-eax-and 0/imm32 + 74/jump-if-= break/disp8 + (write-buffered Stderr Space) + (write-buffered Stderr %eax) + } + (write-buffered Stderr Newline) + (flush Stderr) + (emit-indent Stderr *(ebp+8)) + (write-buffered Stderr "block depth: ") + (write-int32-hex-buffered Stderr *(ebx+0x10)) # Var-block-depth + (write-buffered Stderr Newline) + (flush Stderr) + (emit-indent Stderr *(ebp+8)) + (write-buffered Stderr "stack offset: ") + (write-int32-hex-buffered Stderr *(ebx+0x14)) # Var-offset + (write-buffered Stderr Newline) + (flush Stderr) + (emit-indent Stderr *(ebp+8)) + (write-buffered Stderr "reg: ") + (write-int32-hex-buffered Stderr *(ebx+0x18)) # Var-register + (write-buffered Stderr ",") + (write-int32-hex-buffered Stderr *(ebx+0x1c)) # Var-register + (write-buffered Stderr "->") + (flush Stderr) + (lookup *(ebx+0x18) *(ebx+0x1c)) # Var-register + (write-int32-hex-buffered Stderr %eax) + { + 3d/compare-eax-and 0/imm32 + 74/jump-if-= break/disp8 + (write-buffered Stderr Space) + (write-buffered Stderr %eax) + } + (write-buffered Stderr Newline) + (flush Stderr) + } +$dump-var:end: + # . restore registers + 5b/pop-to-ebx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +####################################################### +# Type-checking +####################################################### + +check-mu-types: # err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + # var curr/eax: (addr function) = lookup(Program->functions) + (lookup *_Program-functions *_Program-functions->payload) # => eax + { +$check-mu-types:loop: + # if (curr == null) break + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= break/disp32 +#? # dump curr->name {{{ +#? 50/push-eax +#? (lookup *eax *(eax+4)) # Function-name Function-name => eax +#? (write-buffered Stderr %eax) +#? (write-buffered Stderr Newline) +#? (flush Stderr) +#? 58/pop-to-eax +#? # }}} + (check-mu-function %eax *(ebp+8) *(ebp+0xc)) + # curr = lookup(curr->next) + (lookup *(eax+0x20) *(eax+0x24)) # Function-next Function-next => eax + e9/jump loop/disp32 + } +$check-mu-types:end: + # . restore registers + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +check-mu-function: # fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 56/push-esi + # esi = f + 8b/-> *(ebp+8) 6/r32/esi + # outputs + (lookup *(esi+0x10) *(esi+0x14)) # Function-outputs Function-outputs => eax + (check-all-unique-registers %eax %esi *(ebp+0xc) *(ebp+0x10)) + # body + (lookup *(esi+0x18) *(esi+0x1c)) # Function-body Function-body => eax + (check-mu-block %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10)) + # if function has no outputs, we're done + 81 7/subop/compare *(esi+0x10) 0/imm32 + 74/jump-if-= $check-mu-function:end/disp8 + # some final checks on body + (check-final-stmt-is-return %eax %esi *(ebp+0xc) *(ebp+0x10)) + (check-no-breaks %eax %esi *(ebp+0xc) *(ebp+0x10)) +$check-mu-function:end: + # . restore registers + 5e/pop-to-esi + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +check-mu-block: # block: (addr block), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + # eax = block + 8b/-> *(ebp+8) 0/r32/eax + # var stmts/eax: (addr list stmt) = lookup(block->statements) + (lookup *(eax+4) *(eax+8)) # Block-stmts Block-stmts => eax + # + { +$check-mu-block:check-empty: + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= break/disp32 + # emit block->statements + (check-mu-stmt-list %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + } +$check-mu-block:end: + # . restore registers + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +check-mu-stmt-list: # stmts: (addr list stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 56/push-esi + # esi = stmts + 8b/-> *(ebp+8) 6/r32/esi + { +$check-mu-stmt-list:loop: + 81 7/subop/compare %esi 0/imm32 + 0f 84/jump-if-= break/disp32 + # var curr-stmt/eax: (addr stmt) = lookup(stmts->value) + (lookup *esi *(esi+4)) # List-value List-value => eax + { +$check-mu-stmt-list:check-for-block: + 81 7/subop/compare *eax 0/imm32/block # Stmt-tag + 75/jump-if-!= break/disp8 +$check-mu-stmt-list:block: + (check-mu-block %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + eb/jump $check-mu-stmt-list:continue/disp8 + } + { +$check-mu-stmt-list:check-for-stmt1: + 81 7/subop/compare *eax 1/imm32/stmt1 # Stmt-tag + 0f 85/jump-if-!= break/disp32 +$check-mu-stmt-list:stmt1: + (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + eb/jump $check-mu-stmt-list:continue/disp8 + } + { +$check-mu-stmt-list:check-for-reg-var-def: + 81 7/subop/compare *eax 3/imm32/reg-var-def # Stmt-tag + 0f 85/jump-if-!= break/disp32 +$check-mu-stmt-list:reg-var-def: + (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + eb/jump $check-mu-stmt-list:continue/disp8 + } +$check-mu-stmt-list:continue: + # TODO: raise an error on unrecognized Stmt-tag + (lookup *(esi+8) *(esi+0xc)) # List-next List-next => eax + 89/<- %esi 0/r32/eax + e9/jump loop/disp32 + } +$check-mu-stmt-list:end: + # . restore registers + 5e/pop-to-esi + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +check-mu-stmt: # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + # - if stmt's operation matches a primitive, check against it + (has-primitive-name? *(ebp+8)) # => eax + 3d/compare-eax-and 0/imm32/false + { + 74/jump-if-= break/disp8 + (check-mu-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + e9/jump $check-mu-stmt:end/disp32 + } + # - otherwise find a function to check against + # var f/eax: (addr function) = lookup(*Program->functions) + (lookup *_Program-functions *_Program-functions->payload) # => eax + (find-matching-function %eax *(ebp+8)) # => eax + 3d/compare-eax-and 0/imm32 + { + 74/jump-if-= break/disp8 + (check-mu-call *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + eb/jump $check-mu-stmt:end/disp8 + } + # var f/eax: (addr function) = lookup(*Program->signatures) + (lookup *_Program-signatures *_Program-signatures->payload) # => eax + (find-matching-function %eax *(ebp+8)) # => eax + 3d/compare-eax-and 0/imm32 + { + 74/jump-if-= break/disp8 + (check-mu-call *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + eb/jump $check-mu-stmt:end/disp8 + } + # - otherwise abort + e9/jump $check-mu-stmt:unknown-call/disp32 +$check-mu-stmt:end: + # . restore registers + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$check-mu-stmt:unknown-call: + (write-buffered *(ebp+0x10) "unknown function '") + 8b/-> *(ebp+8) 0/r32/eax + (lookup *(eax+4) *(eax+8)) # Stmt1-operation Stmt1-operation => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "'\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +has-primitive-name?: # stmt: (addr stmt) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + 56/push-esi + # var name/esi: (addr array byte) = lookup(stmt->operation) + 8b/-> *(ebp+8) 6/r32/esi + (lookup *(esi+4) *(esi+8)) # Stmt1-operation Stmt1-operation => eax + 89/<- %esi 0/r32/eax + # if (name == "return") return true + (string-equal? %esi "return") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $has-primitive-name?:end/disp32 + # if (name == "get") return true + (string-equal? %esi "get") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $has-primitive-name?:end/disp32 + # if (name == "index") return true + (string-equal? %esi "index") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $has-primitive-name?:end/disp32 + # if (name == "length") return true + (string-equal? %esi "length") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $has-primitive-name?:end/disp32 + # if (name == "compute-offset") return true + (string-equal? %esi "compute-offset") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $has-primitive-name?:end/disp32 + # if (name == "copy-object") return true + (string-equal? %esi "copy-object") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $has-primitive-name?:end/disp32 + # if (name == "clear-object") return true + (string-equal? %esi "clear-object") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $has-primitive-name?:end/disp32 + # if (name == "allocate") return true + (string-equal? %esi "allocate") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $has-primitive-name?:end/disp32 + # if (name == "populate") return true + (string-equal? %esi "populate") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $has-primitive-name?:end/disp32 + # if (name == "populate-stream") return true + (string-equal? %esi "populate-stream") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $has-primitive-name?:end/disp32 + # if (name == "read-from-stream") return true + (string-equal? %esi "read-from-stream") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $has-primitive-name?:end/disp32 + # if (name == "write-to-stream") return true + (string-equal? %esi "write-to-stream") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $has-primitive-name?:end/disp32 + # var curr/ecx: (addr primitive) = Primitives + b9/copy-to-ecx Primitives/imm32 + { +$has-primitive-name?:loop: + # if (curr == null) break + 81 7/subop/compare %ecx 0/imm32 + 74/jump-if-= break/disp8 + # if (primitive->name == name) return true + (lookup *ecx *(ecx+4)) # Primitive-name Primitive-name => eax +#? (write-buffered Stderr %eax) +#? (write-buffered Stderr Newline) +#? (flush Stderr) + (string-equal? %esi %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= $has-primitive-name?:end/disp8 +$has-primitive-name?:next-primitive: + # curr = curr->next + (lookup *(ecx+0x3c) *(ecx+0x40)) # Primitive-next Primitive-next => eax + 89/<- %ecx 0/r32/eax + # + e9/jump loop/disp32 + } + # return null + b8/copy-to-eax 0/imm32 +$has-primitive-name?:end: + # . restore registers + 5e/pop-to-esi + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +check-mu-primitive: # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + # var op/ecx: (addr array byte) = lookup(stmt->operation) + 8b/-> *(ebp+8) 0/r32/eax + (lookup *(eax+4) *(eax+8)) # Stmt1-operation Stmt1-operation => eax + 89/<- %ecx 0/r32/eax + # if (op == "copy") check-mu-copy-stmt + { + (string-equal? %ecx "copy") # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (check-mu-copy-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + e9/jump $check-mu-primitive:end/disp32 + } + # if (op == "copy-to") check-mu-copy-to-stmt + { + (string-equal? %ecx "copy-to") # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (check-mu-copy-to-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + e9/jump $check-mu-primitive:end/disp32 + } + # if (op == "copy-byte") check-mu-copy-byte-stmt + { + (string-equal? %ecx "copy-byte") # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (check-mu-copy-byte-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + e9/jump $check-mu-primitive:end/disp32 + } + # if (op == "copy-byte-to") check-mu-copy-byte-to-stmt + { + (string-equal? %ecx "copy-byte-to") # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (check-mu-copy-byte-to-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + e9/jump $check-mu-primitive:end/disp32 + } + # if (op == "compare") check-mu-compare-stmt + { + (string-equal? %ecx "compare") # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (check-mu-compare-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + e9/jump $check-mu-primitive:end/disp32 + } + # if (op == "address") check-mu-address-stmt + { + (string-equal? %ecx "address") # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (check-mu-address-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + e9/jump $check-mu-primitive:end/disp32 + } + # if (op == "return") check-mu-return-stmt + { + (string-equal? %ecx "return") # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (check-mu-return-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + e9/jump $check-mu-primitive:end/disp32 + } + # if (op == "get") check-mu-get-stmt + { + (string-equal? %ecx "get") # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (check-mu-get-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + e9/jump $check-mu-primitive:end/disp32 + } + # if (op == "index") check-mu-index-stmt + { + (string-equal? %ecx "index") # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (check-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + e9/jump $check-mu-primitive:end/disp32 + } + # if (op == "length") check-mu-length-stmt + { + (string-equal? %ecx "length") # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (check-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + e9/jump $check-mu-primitive:end/disp32 + } + # if (op == "compute-offset") check-mu-compute-offset-stmt + { + (string-equal? %ecx "compute-offset") # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (check-mu-compute-offset-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + e9/jump $check-mu-primitive:end/disp32 + } + # if (op == "copy-object") check-mu-copy-object-stmt + { + (string-equal? %ecx "copy-object") # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (check-mu-copy-object-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + e9/jump $check-mu-primitive:end/disp32 + } + # if (op == "clear-object") check-mu-clear-object-stmt + { + (string-equal? %ecx "clear-object") # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (check-mu-clear-object-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + e9/jump $check-mu-primitive:end/disp32 + } + # if (op == "allocate") check-mu-allocate-stmt + { + (string-equal? %ecx "allocate") # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (check-mu-allocate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + e9/jump $check-mu-primitive:end/disp32 + } + # if (op == "populate") check-mu-populate-stmt + { + (string-equal? %ecx "populate") # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (check-mu-populate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + e9/jump $check-mu-primitive:end/disp32 + } + # if (op == "populate-stream") check-mu-populate-stream-stmt + { + (string-equal? %ecx "populate-stream") # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (check-mu-populate-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + e9/jump $check-mu-primitive:end/disp32 + } + # if (op == "read-from-stream") check-mu-read-from-stream-stmt + { + (string-equal? %ecx "read-from-stream") # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (check-mu-read-from-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + e9/jump $check-mu-primitive:end/disp32 + } + # if (op == "write-to-stream") check-mu-write-to-stream-stmt + { + (string-equal? %ecx "write-to-stream") # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (check-mu-write-to-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + e9/jump $check-mu-primitive:end/disp32 + } + # if (op == "convert") check-mu-convert-stmt + { + (string-equal? %ecx "convert") # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (check-mu-convert-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + e9/jump $check-mu-primitive:end/disp32 + } + # otherwise check-numberlike-stmt + (check-mu-numberlike-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) +$check-mu-primitive:end: + # . restore registers + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# by default, Mu primitives should only operate on 'number-like' types +check-mu-numberlike-primitive: # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 56/push-esi + # esi = stmt + 8b/-> *(ebp+8) 6/r32/esi + # var gas/ecx: int = 2 + b9/copy-to-ecx 2/imm32 + # - check at most 1 output + # var output/eax: (addr stmt-var) = stmt->outputs + (lookup *(esi+0x14) *(esi+0x18)) # Stmt1-outputs Stmt1-outputs => eax + { + 3d/compare-eax-and 0/imm32 + 74/jump-if-= break/disp8 +$check-mu-numberlike-primitive:output: + (check-mu-numberlike-output %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-mu-numberlike-primitive:error-too-many-outputs/disp32 + # check output is in a register + # --gas + 49/decrement-ecx + } + # - check first inout + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + { + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-numberlike-primitive:end/disp32 +$check-mu-numberlike-primitive:first-inout: + (check-mu-numberlike-arg %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + # --gas + 49/decrement-ecx + } + # - check second inout + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax + { + 3d/compare-eax-and 0/imm32 + 74/jump-if-= $check-mu-numberlike-primitive:end/disp8 +$check-mu-numberlike-primitive:second-inout: + # is a second inout allowed? + 81 7/subop/compare %ecx 0/imm32 + 0f 84/jump-if-= $check-mu-numberlike-primitive:error-too-many-inouts/disp32 +$check-mu-numberlike-primitive:second-inout-permitted: + (check-mu-numberlike-arg %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + } +$check-mu-numberlike-primitive:third-inout: + # if there's a third arg, raise an error + 81 7/subop/compare *(eax+8) 0/imm32 # Stmt-var-next + 0f 85/jump-if-!= $check-mu-numberlike-primitive:error-too-many-inouts/disp32 +$check-mu-numberlike-primitive:end: + # . restore registers + 5e/pop-to-esi + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$check-mu-numberlike-primitive:error-too-many-inouts: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt ") + (lookup *(esi+4) *(esi+8)) # Stmt1-operation Stmt1-operation => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": too many inouts; most primitives support at most two arguments, across inouts and outputs\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-numberlike-primitive:error-too-many-outputs: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt ") + (lookup *(esi+4) *(esi+8)) # Stmt1-operation Stmt1-operation => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": too many outputs; most primitives support at most one output\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +check-mu-numberlike-arg: # v: (addr stmt-var), stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 56/push-esi + # var t/esi: (addr type-tree) = lookup(v->value->type) + 8b/-> *(ebp+8) 0/r32/eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + 89/<- %esi 0/r32/eax +$check-mu-numberlike-arg:check-literal: + # if t is an int, return + (is-simple-mu-type? %esi 0) # literal => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $check-mu-numberlike-arg:end/disp32 +$check-mu-numberlike-arg:check-addr: + # if t is an addr and v is dereferenced, return whether t->payload is an addr + { + (is-mu-addr-type? %esi) # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + 8b/-> *(ebp+8) 0/r32/eax + 8b/-> *(eax+0x10) 0/r32/eax # Stmt-var-is-deref + 3d/compare-eax-and 0/imm32/false + { + 74/jump-if-= break/disp8 + (lookup *(esi+0xc) *(esi+0x10)) # Type-tree-right Type-tree-right => eax + # if t->right is null, t = t->left + 81 7/subop/compare *(eax+0xc) 0/imm32 # Type-tree-right + { + 75/jump-if-!= break/disp8 + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } + (is-mu-addr-type? %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= $check-mu-numberlike-arg:end/disp8 + } + } +$check-mu-numberlike-arg:output-checks: + (check-mu-numberlike-output *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18)) +$check-mu-numberlike-arg:end: + # . restore registers + 5e/pop-to-esi + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +check-mu-numberlike-output: # v: (addr stmt-var), stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + # + (is-mu-numberlike-output-var? *(ebp+8)) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-numberlike-output:fail/disp32 +$check-mu-numberlike-output:end: + # . restore registers + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$check-mu-numberlike-output:fail: + # otherwise raise an error + (write-buffered *(ebp+0x14) "fn ") + 8b/-> *(ebp+0x10) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x14) %eax) + (write-buffered *(ebp+0x14) ": stmt ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *(eax+4) *(eax+8)) # Stmt1-operation Stmt1-operation => eax + (write-buffered *(ebp+0x14) %eax) + (write-buffered *(ebp+0x14) ": '") + 8b/-> *(ebp+8) 0/r32/eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x14) %eax) + (write-buffered *(ebp+0x14) "' must be a non-addr non-offset scalar\n") + (flush *(ebp+0x14)) + (stop *(ebp+0x18) 1) + # never gets here + +is-mu-numberlike-output-var?: # v: (addr stmt-var) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # + 8b/-> *(ebp+8) 0/r32/eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + (is-mu-numberlike-output? %eax) # => eax +$is-mu-numberlike-output-var?:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +is-mu-numberlike-output?: # v: (addr type-tree) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 56/push-esi + # var t/esi: (addr type-tree) = lookup(v->value->type) + 8b/-> *(ebp+8) 6/r32/esi +$is-mu-numberlike-output?:check-int: + # if t is an int, return + (is-simple-mu-type? %esi 1) # int => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $is-mu-numberlike-output?:return-true/disp32 +$is-mu-numberlike-output?:check-float: + # if t is a float, return + (is-simple-mu-type? %esi 0xf) # float => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= $is-mu-numberlike-output?:return-true/disp8 +$is-mu-numberlike-output?:check-boolean: + # if t is a boolean, return + (is-simple-mu-type? %esi 5) # boolean => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= $is-mu-numberlike-output?:return-true/disp8 +$is-mu-numberlike-output?:check-byte: + # if t is a byte, return + (is-simple-mu-type? %esi 8) # byte => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= $is-mu-numberlike-output?:return-true/disp8 +$is-mu-numberlike-output?:check-code-point: + # if t is a code-point, return + (is-simple-mu-type? %esi 0xd) # code-point => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= $is-mu-numberlike-output?:return-true/disp8 +$is-mu-numberlike-output?:check-grapheme: + # if t is a grapheme, return + (is-simple-mu-type? %esi 0xe) # grapheme => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= $is-mu-numberlike-output?:return-true/disp8 +$is-mu-numberlike-output?:return-false: + b8/copy-to-eax 0/imm32/false + eb/jump $is-mu-numberlike-output?:end/disp8 +$is-mu-numberlike-output?:return-true: + b8/copy-to-eax 1/imm32/true +$is-mu-numberlike-output?:end: + # . restore registers + 5e/pop-to-esi + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +check-mu-copy-stmt: # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 56/push-esi + 57/push-edi + # var type-parameters/edx: (addr table (handle array byte) (addr type-tree) 8) + 81 5/subop/subtract %esp 0x60/imm32 + 68/push 0x60/imm32/size + 68/push 0/imm32/read + 68/push 0/imm32/write + 89/<- %edx 4/r32/esp +$check-mu-copy-stmt:get-output: + # esi = stmt + 8b/-> *(ebp+8) 6/r32/esi + # var output/edi: (addr stmt-var) = stmt->outputs + (lookup *(esi+0x14) *(esi+0x18)) # Stmt1-outputs Stmt1-outputs => eax + 89/<- %edi 0/r32/eax + # zero outputs + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-copy-stmt:error-no-output/disp32 + # > 1 output + (lookup *(edi+8) *(edi+0xc)) # Stmt-var-next Stmt-var-next => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-mu-copy-stmt:error-too-many-outputs/disp32 +$check-mu-copy-stmt:get-inout: + # var inout/esi: (addr stmt-var) = stmt->inouts + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 89/<- %esi 0/r32/eax + # zero inouts + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-copy-stmt:error-no-inout/disp32 + # > 1 inout + (lookup *(esi+8) *(esi+0xc)) # Stmt-var-next Stmt-var-next => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-mu-copy-stmt:error-too-many-inouts/disp32 +$check-mu-copy-stmt:types: + # if inout is not a scalar, abort + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (size-of %eax) # => eax + 3d/compare-eax-and 4/imm32 + 0f 8f/jump-if-> $check-mu-copy-stmt:error-inout-too-large/disp32 + # var inout-type/ecx: (addr type-tree) = inout->value->type + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + 89/<- %ecx 0/r32/eax + # if (inout->is-deref?) inout-type = inout-type->payload + 8b/-> *(esi+0x10) 0/r32/eax # Stmt-var-is-deref + 3d/compare-eax-and 0/imm32/false + { + 74/jump-if-= break/disp8 + (lookup *(ecx+0xc) *(ecx+0x10)) # Type-tree-right Type-tree-right => eax + # if inout-type->right is null, t = inout-type->left + 81 7/subop/compare *(eax+0xc) 0/imm32 # Type-tree-right + { + 75/jump-if-!= break/disp8 + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } + 89/<- %ecx 0/r32/eax + } + # if output not in register, abort + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-copy-stmt:error-output-not-in-register/disp32 + # var output-type/eax: (addr type-tree) = output->value->type + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + # if (inout-type == output-type) return + (type-match? %eax %ecx %edx) # => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-mu-copy-stmt:end/disp32 + # if output is an addr and inout is 0, return + { + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + (is-mu-addr-type? %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (string-equal? %eax "0") # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + e9/jump $check-mu-copy-stmt:end/disp32 + } + # if output is an offset and inout is 0, return + { + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + 81 7/subop/compare *eax 0/imm32/false # Type-tree-is-atom + 75/jump-if-!= break/disp8 + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 7) # offset => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (string-equal? %eax "0") # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + e9/jump $check-mu-copy-stmt:end/disp32 + } + # if output is a byte, abort if inout is not a literal. Otherwise return. + { + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + (is-simple-mu-type? %eax 8) # byte => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + (is-simple-mu-type? %eax 0) # literal => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-copy-stmt:error-non-literal-to-byte/disp32 + eb/jump $check-mu-copy-stmt:end/disp8 + } + # if output is not number-like, abort + (check-mu-numberlike-output %edi *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) +$check-mu-copy-stmt:end: + # . reclaim locals + 81 0/subop/add %esp 0x6c/imm32 + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$check-mu-copy-stmt:error-no-inout: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'copy' expects an inout\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-copy-stmt:error-too-many-inouts: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'copy' must have just one inout\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-copy-stmt:error-no-output: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'copy' expects an output\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-copy-stmt:error-output-not-in-register: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt copy: output '") + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' not in a register\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-copy-stmt:error-too-many-outputs: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'copy' must have just one output\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-copy-stmt:error-inout-too-large: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt copy: '") + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' is too large to fit in a register\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-copy-stmt:error-non-literal-to-byte: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt copy: cannot copy non-literal to '") + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' of type byte; use copy-byte\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +check-mu-copy-to-stmt: # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + 57/push-edi + # var type-parameters/edx: (addr table (handle array byte) (addr type-tree) 8) + 81 5/subop/subtract %esp 0x60/imm32 + 68/push 0x60/imm32/size + 68/push 0/imm32/read + 68/push 0/imm32/write + 89/<- %edx 4/r32/esp + # esi = stmt + 8b/-> *(ebp+8) 6/r32/esi +$check-mu-copy-to-stmt:check-for-output: + # if stmt->outputs abort + (lookup *(esi+0x14) *(esi+0x18)) # Stmt1-outputs Stmt1-outputs => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-mu-copy-to-stmt:error-too-many-outputs/disp32 +$check-mu-copy-to-stmt:get-dest: + # var dest/edi: (addr stmt-var) = stmt->inouts + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 89/<- %edi 0/r32/eax + # zero inouts + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-copy-to-stmt:error-incorrect-inouts/disp32 +$check-mu-copy-to-stmt:get-src: + # var src/esi: (addr stmt-var) = dest->next + (lookup *(edi+8) *(edi+0xc)) # Stmt-var-next Stmt-var-next => eax + 89/<- %esi 0/r32/eax + # 1 inout + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-copy-to-stmt:error-incorrect-inouts/disp32 + # > 2 inouts + (lookup *(esi+8) *(esi+0xc)) # Stmt-var-next Stmt-var-next => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-mu-copy-to-stmt:error-incorrect-inouts/disp32 +$check-mu-copy-to-stmt:types: + # if src is not a scalar, abort + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (size-of %eax) # => eax + 3d/compare-eax-and 4/imm32 + 0f 8f/jump-if-> $check-mu-copy-to-stmt:error-src-too-large/disp32 + # var src-type/ecx: (addr type-tree) = src->value->type + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + 89/<- %ecx 0/r32/eax + # if src not in register or literal, abort + # (we can't use stack-offset because it hasn't been computed yet) + { + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+0x8) *(eax+0xc)) # Var-type Var-type => eax + (is-simple-mu-type? %eax 0) # => eax + 3d/compare-eax-and 0/imm32 + 75/jump-if-!= break/disp8 + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + 3d/compare-eax-and 0/imm32 + 75/jump-if-!= break/disp8 + e9/jump $check-mu-copy-to-stmt:error-src-not-literal-or-in-register/disp32 + } + # var dest-type/ebx: (addr type-tree) = dest->value->type + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + 89/<- %ebx 0/r32/eax + # if (dest->is-deref?) dest-type = dest-type->payload +$check-mu-copy-to-stmt:check-dest-deref: + 8b/-> *(edi+0x10) 0/r32/eax # Stmt-var-is-deref + 3d/compare-eax-and 0/imm32/false + { + 74/jump-if-= break/disp8 + (lookup *(ebx+0xc) *(ebx+0x10)) # Type-tree-right Type-tree-right => eax +$check-mu-copy-to-stmt:dest-is-deref: + # if dest-type->right is null, dest-type = dest-type->left + 81 7/subop/compare *(eax+0xc) 0/imm32 # Type-tree-right + { + 75/jump-if-!= break/disp8 +$check-mu-copy-to-stmt:dest-is-deref2: + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } + 89/<- %ebx 0/r32/eax + } + # if dest is a byte and src is not a literal, abort + { +$check-mu-copy-to-stmt:final-check-byte: + (is-simple-mu-type? %ebx 8) # byte => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (is-simple-mu-type? %ecx 0) # literal => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-copy-to-stmt:error-non-literal-to-byte/disp32 + } + # if (src-type == dest-type) return + (type-match? %ebx %ecx %edx) # => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-mu-copy-to-stmt:end/disp32 + # if dest is an addr and src is 0, return + { +$check-mu-copy-to-stmt:final-check-addr: + (is-mu-addr-type? %ebx) # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (string-equal? %eax "0") # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + e9/jump $check-mu-copy-to-stmt:end/disp32 + } + # if dest is an offset and src is 0, return + { +$check-mu-copy-to-stmt:final-check-offset: + 81 7/subop/compare *ebx 0/imm32/false # Type-tree-is-atom + 75/jump-if-!= break/disp8 + (lookup *(ebx+4) *(ebx+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 7) # offset => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (string-equal? %eax "0") # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + e9/jump $check-mu-copy-to-stmt:end/disp32 + } + # if dest is not number-like, abort + (check-mu-numberlike-arg %edi *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) +$check-mu-copy-to-stmt:end: + # . reclaim locals + 81 0/subop/add %esp 0x6c/imm32 + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$check-mu-copy-to-stmt:error-incorrect-inouts: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'copy-to' must have two inouts\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-copy-to-stmt:error-too-many-outputs: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'copy-to' must not have any outputs\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-copy-to-stmt:error-src-not-literal-or-in-register: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt copy-to: source (second inout) is in memory\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-copy-to-stmt:error-src-too-large: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt copy-to: '") + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' is too large to copy\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-copy-to-stmt:error-non-literal-to-byte: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt copy-to: cannot copy non-literal to type byte; use copy-byte-to\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +check-mu-copy-byte-stmt: # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 56/push-esi + 57/push-edi + # var type-parameters/edx: (addr table (handle array byte) (addr type-tree) 8) + 81 5/subop/subtract %esp 0x60/imm32 + 68/push 0x60/imm32/size + 68/push 0/imm32/read + 68/push 0/imm32/write + 89/<- %edx 4/r32/esp +$check-mu-copy-byte-stmt:get-output: + # esi = stmt + 8b/-> *(ebp+8) 6/r32/esi + # var output/edi: (addr stmt-var) = stmt->outputs + (lookup *(esi+0x14) *(esi+0x18)) # Stmt1-outputs Stmt1-outputs => eax + 89/<- %edi 0/r32/eax + # zero outputs + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-copy-byte-stmt:error-no-output/disp32 + # > 1 output + (lookup *(edi+8) *(edi+0xc)) # Stmt-var-next Stmt-var-next => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-mu-copy-byte-stmt:error-too-many-outputs/disp32 +$check-mu-copy-byte-stmt:get-inout: + # var inout/esi: (addr stmt-var) = stmt->inouts + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 89/<- %esi 0/r32/eax + # zero inouts + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-copy-byte-stmt:error-no-inout/disp32 + # > 1 inout + (lookup *(esi+8) *(esi+0xc)) # Stmt-var-next Stmt-var-next => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-mu-copy-byte-stmt:error-too-many-inouts/disp32 +$check-mu-copy-byte-stmt:types: + # if inout is not a scalar, abort + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (size-of %eax) # => eax + 3d/compare-eax-and 4/imm32 + 0f 8f/jump-if-> $check-mu-copy-byte-stmt:error-inout-too-large/disp32 + # var inout-type/ecx: (addr type-tree) = inout->value->type + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + 89/<- %ecx 0/r32/eax +$check-mu-copy-byte-stmt:check-inout-deref: + # if (inout->is-deref?) inout-type = inout-type->payload + 8b/-> *(esi+0x10) 0/r32/eax # Stmt-var-is-deref + 3d/compare-eax-and 0/imm32/false + { + 74/jump-if-= break/disp8 +$check-mu-copy-byte-stmt:inout-is-deref: + (lookup *(ecx+0xc) *(ecx+0x10)) # Type-tree-right Type-tree-right => eax + # if inout-type->right is null, t = inout-type->left + 81 7/subop/compare *(eax+0xc) 0/imm32 # Type-tree-right + { + 75/jump-if-!= break/disp8 +$check-mu-copy-byte-stmt:inout-is-deref2: + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } + 89/<- %ecx 0/r32/eax + } + # if output not in register, abort + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-copy-byte-stmt:error-output-not-in-register/disp32 + # var output-type/eax: (addr type-tree) = output->value->type + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + # if output is not of type byte, abort + (is-simple-mu-type? %eax 8) # byte => eax + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-copy-byte-stmt:error-invalid-output-type/disp32 +$check-mu-copy-byte-stmt:end: + # . reclaim locals + 81 0/subop/add %esp 0x6c/imm32 + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$check-mu-copy-byte-stmt:error-no-inout: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'copy-byte' expects an inout\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-copy-byte-stmt:error-too-many-inouts: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'copy-byte' must have just one inout\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-copy-byte-stmt:error-no-output: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'copy-byte' expects an output\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-copy-byte-stmt:error-output-not-in-register: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt copy-byte: output '") + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' not in a register\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-copy-byte-stmt:error-too-many-outputs: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'copy-byte' must have just one output\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-copy-byte-stmt:error-invalid-output-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'copy-byte' must write to output of type byte\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-copy-byte-stmt:error-inout-too-large: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt copy-byte: '") + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' is too large to fit in a register\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +check-mu-copy-byte-to-stmt: # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 52/push-edx + 53/push-ebx + 56/push-esi + 57/push-edi + # var type-parameters/edx: (addr table (handle array byte) (addr type-tree) 8) + 81 5/subop/subtract %esp 0x60/imm32 + 68/push 0x60/imm32/size + 68/push 0/imm32/read + 68/push 0/imm32/write + 89/<- %edx 4/r32/esp + # esi = stmt + 8b/-> *(ebp+8) 6/r32/esi +$check-mu-copy-byte-to-stmt:check-for-output: + # if stmt->outputs abort + (lookup *(esi+0x14) *(esi+0x18)) # Stmt1-outputs Stmt1-outputs => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-mu-copy-byte-to-stmt:error-too-many-outputs/disp32 +$check-mu-copy-byte-to-stmt:get-dest: + # var dest/edi: (addr stmt-var) = stmt->inouts + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 89/<- %edi 0/r32/eax + # zero inouts + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-copy-byte-to-stmt:error-incorrect-inouts/disp32 +$check-mu-copy-byte-to-stmt:get-src: + # var src/esi: (addr stmt-var) = dest->next + (lookup *(edi+8) *(edi+0xc)) # Stmt-var-next Stmt-var-next => eax + 89/<- %esi 0/r32/eax + # 1 inout + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-copy-byte-to-stmt:error-incorrect-inouts/disp32 + # > 2 inouts + (lookup *(esi+8) *(esi+0xc)) # Stmt-var-next Stmt-var-next => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-mu-copy-byte-to-stmt:error-incorrect-inouts/disp32 +$check-mu-copy-byte-to-stmt:types: + # if src is not a scalar, abort + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (size-of %eax) # => eax + 3d/compare-eax-and 4/imm32 + 0f 8f/jump-if-> $check-mu-copy-byte-to-stmt:error-src-too-large/disp32 + # if src not in register, abort + { + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + 3d/compare-eax-and 0/imm32 + 75/jump-if-!= break/disp8 + e9/jump $check-mu-copy-byte-to-stmt:error-src-not-in-register/disp32 + } + # var dest-type/ebx: (addr type-tree) = dest->value->type + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + 89/<- %ebx 0/r32/eax + # if (dest->is-deref?) dest-type = dest-type->payload +$check-mu-copy-byte-to-stmt:check-dest-deref: + 8b/-> *(edi+0x10) 0/r32/eax # Stmt-var-is-deref + 3d/compare-eax-and 0/imm32/false + { + 74/jump-if-= break/disp8 + (lookup *(ebx+0xc) *(ebx+0x10)) # Type-tree-right Type-tree-right => eax +$check-mu-copy-byte-to-stmt:dest-is-deref: + # if dest-type->right is null, dest-type = dest-type->left + 81 7/subop/compare *(eax+0xc) 0/imm32 # Type-tree-right + { + 75/jump-if-!= break/disp8 +$check-mu-copy-byte-to-stmt:dest-is-deref2: + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } + 89/<- %ebx 0/r32/eax + } + # if dest is not a byte, abort + (is-simple-mu-type? %ebx 8) # byte => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-copy-byte-to-stmt:error-invalid-dest-type/disp32 +$check-mu-copy-byte-to-stmt:end: + # . reclaim locals + 81 0/subop/add %esp 0x6c/imm32 + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$check-mu-copy-byte-to-stmt:error-incorrect-inouts: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'copy-byte-to' must have two inouts\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-copy-byte-to-stmt:error-too-many-outputs: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'copy-byte-to' must not have any outputs\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-copy-byte-to-stmt:error-src-not-in-register: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt copy-byte-to: source (second inout) must be in a register\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-copy-byte-to-stmt:error-invalid-dest-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt copy-byte-to: '") + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' must be a byte\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-copy-byte-to-stmt:error-src-too-large: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt copy-byte-to: '") + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' is too large to copy\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +check-mu-compare-stmt: # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + 57/push-edi + # var type-parameters/edx: (addr table (handle array byte) (addr type-tree) 8) + 81 5/subop/subtract %esp 0x60/imm32 + 68/push 0x60/imm32/size + 68/push 0/imm32/read + 68/push 0/imm32/write + 89/<- %edx 4/r32/esp + # esi = stmt + 8b/-> *(ebp+8) 6/r32/esi +$check-mu-compare-stmt:check-for-output: + # if stmt->outputs abort + (lookup *(esi+0x14) *(esi+0x18)) # Stmt1-outputs Stmt1-outputs => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-mu-compare-stmt:error-too-many-outputs/disp32 +$check-mu-compare-stmt:get-left: + # var left/edi: (addr stmt-var) = stmt->inouts + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 89/<- %edi 0/r32/eax + # zero inouts + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-compare-stmt:error-incorrect-inouts/disp32 +$check-mu-compare-stmt:get-right: + # var right/esi: (addr stmt-var) = left->next + (lookup *(edi+8) *(edi+0xc)) # Stmt-var-next Stmt-var-next => eax + 89/<- %esi 0/r32/eax + # 1 inout + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-compare-stmt:error-incorrect-inouts/disp32 + # > 2 inouts + (lookup *(esi+8) *(esi+0xc)) # Stmt-var-next Stmt-var-next => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-mu-compare-stmt:error-incorrect-inouts/disp32 + # if both inouts are in memory, abort + { +$check-mu-compare-stmt:both-in-mem: + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+0x8) *(eax+0xc)) # Var-type Var-type => eax + (is-simple-mu-type? %eax 0) # => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= break/disp32 + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + 3d/compare-eax-and 0/imm32 + 75/jump-if-!= break/disp8 + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+0x8) *(eax+0xc)) # Var-type Var-type => eax + (is-simple-mu-type? %eax 0) # => eax + 3d/compare-eax-and 0/imm32 + 75/jump-if-!= break/disp8 + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + 3d/compare-eax-and 0/imm32 + 75/jump-if-!= break/disp8 + e9/jump $check-mu-compare-stmt:error-both-in-memory/disp32 + } +$check-mu-compare-stmt:types: + # var right-type/ecx: (addr type-tree) = right->value->type + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + 89/<- %ecx 0/r32/eax + # if (right->is-deref?) right-type = right-type->payload + 8b/-> *(esi+0x10) 0/r32/eax # Stmt-var-is-deref + 3d/compare-eax-and 0/imm32/false + { + 74/jump-if-= break/disp8 + (lookup *(ecx+0xc) *(ecx+0x10)) # Type-tree-right Type-tree-right => eax + # if right-type->right is null, right-type = right-type->left + 81 7/subop/compare *(eax+0xc) 0/imm32 # Type-tree-right + { + 75/jump-if-!= break/disp8 + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } + 89/<- %ecx 0/r32/eax + } + # if right-type is a literal string, abort + (is-simple-mu-type? %ecx 0x10) # string-literal => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $check-mu-compare-stmt:error-right-string-literal/disp32 + # if right is not a scalar, abort + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (size-of %eax) # => eax + 3d/compare-eax-and 4/imm32 + 0f 8f/jump-if-> $check-mu-compare-stmt:error-right-too-large/disp32 + # if left is not a scalar, abort + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (size-of %eax) # => eax + 3d/compare-eax-and 4/imm32 + 0f 8f/jump-if-> $check-mu-compare-stmt:error-left-too-large/disp32 + # var left-type/ebx: (addr type-tree) = left->value->type + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + 89/<- %ebx 0/r32/eax + # if (left->is-deref?) left-type = left-type->payload + 8b/-> *(edi+0x10) 0/r32/eax # Stmt-var-is-deref + 3d/compare-eax-and 0/imm32/false + { + 74/jump-if-= break/disp8 + (lookup *(ebx+0xc) *(ebx+0x10)) # Type-tree-right Type-tree-right => eax + # if left-type->right is null, left-type = left-type->left + 81 7/subop/compare *(eax+0xc) 0/imm32 # Type-tree-right + { + 75/jump-if-!= break/disp8 + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } + 89/<- %ebx 0/r32/eax + } + # if (left-type == right-type) return + (type-match? %ebx %ecx %edx) # => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-mu-compare-stmt:end/disp32 + # if left is an addr and right is 0, return + { + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + (is-mu-addr-type? %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (string-equal? %eax "0") # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + eb/jump $check-mu-compare-stmt:end/disp8 + } + # if left is not number-like, abort + (check-mu-numberlike-arg %edi *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) +$check-mu-compare-stmt:end: + # . reclaim locals + 81 0/subop/add %esp 0x6c/imm32 + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$check-mu-compare-stmt:error-incorrect-inouts: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'compare' must have two inouts\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-compare-stmt:error-too-many-outputs: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'compare' must not have any outputs\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-compare-stmt:error-both-in-memory: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt compare: both inouts are in memory\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-compare-stmt:error-left-too-large: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt compare: '") + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' is too large to compare\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-compare-stmt:error-right-too-large: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt compare: '") + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' is too large to compare\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-compare-stmt:error-right-string-literal: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt compare: string literal ") + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) " is not supported; use the string-equal? function\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +check-mu-address-stmt: # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 56/push-esi + 57/push-edi +$check-mu-address-stmt:get-output: + # esi = stmt + 8b/-> *(ebp+8) 6/r32/esi + # var output/edi: (addr stmt-var) = stmt->outputs + (lookup *(esi+0x14) *(esi+0x18)) # Stmt1-outputs Stmt1-outputs => eax + 89/<- %edi 0/r32/eax + # zero outputs + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-address-stmt:error-no-output/disp32 + # > 1 output + (lookup *(edi+8) *(edi+0xc)) # Stmt-var-next Stmt-var-next => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-mu-address-stmt:error-too-many-outputs/disp32 +$check-mu-address-stmt:get-inout: + # var inout/esi: (addr stmt-var) = stmt->inouts + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 89/<- %esi 0/r32/eax + # zero inouts + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-address-stmt:error-no-inout/disp32 + # > 1 inout + (lookup *(esi+8) *(esi+0xc)) # Stmt-var-next Stmt-var-next => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-mu-address-stmt:error-too-many-inouts/disp32 +$check-mu-address-stmt:types: + # if output not in register, abort + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-address-stmt:error-output-not-in-register/disp32 + # var output-type/edx: (addr type-tree) = output->value->type + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + 89/<- %edx 0/r32/eax + # if output-type not an addr, abort + (is-mu-addr-type? %edx) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-address-stmt:error-output-not-address/disp32 + # output-type = output-type->right + (lookup *(edx+0xc) *(edx+0x10)) # Type-tree-right Type-tree-right => eax + # if output-type->right is null, output-type = output-type->left + 81 7/subop/compare *(eax+0xc) 0/imm32 # Type-tree-right + { + 75/jump-if-!= break/disp8 + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } + 89/<- %edx 0/r32/eax + # var inout-type/ecx: (addr type-tree) = inout->value->type + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + 89/<- %ecx 0/r32/eax + # if (inout->is-deref?) inout-type = inout-type->payload + 8b/-> *(esi+0x10) 0/r32/eax # Stmt-var-is-deref + 3d/compare-eax-and 0/imm32/false + { + 74/jump-if-= break/disp8 + (lookup *(ecx+0xc) *(ecx+0x10)) # Type-tree-right Type-tree-right => eax + # if inout-type->right is null, t = inout-type->left + 81 7/subop/compare *(eax+0xc) 0/imm32 # Type-tree-right + { + 75/jump-if-!= break/disp8 + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } + 89/<- %ecx 0/r32/eax + } + # if (inout-type != output-type) abort + (type-equal-ignoring-capacity? %edx %ecx) # => eax + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-address-stmt:error-type-mismatch/disp32 +$check-mu-address-stmt:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$check-mu-address-stmt:error-no-inout: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'address' expects an inout\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-address-stmt:error-too-many-inouts: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'address' must have just one inout\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-address-stmt:error-no-output: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'address' expects an output\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-address-stmt:error-output-not-in-register: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt address: output '") + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' not in a register\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-address-stmt:error-too-many-outputs: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'address' must have just one output\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-address-stmt:error-output-not-address: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt address: output '") + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' is not an addr\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-address-stmt:error-type-mismatch: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt address: output '") + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' cannot hold address of '") + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "'\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +type-equal-ignoring-capacity?: # a: (addr type-tree), b: (addr type-tree) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + 52/push-edx + 53/push-ebx + # var curr-a/ecx: (addr type-tree) = a + 8b/-> *(ebp+8) 1/r32/ecx + # var curr-b/ebx: (addr type-tree) = b + 8b/-> *(ebp+0xc) 3/r32/ebx + # if (curr-a->is-atom?) fall back to regular equality + 81 7/subop/compare *ecx 0/imm32/false # Type-tree-is-atom + 0f 85/jump-if-!= $type-equal-ignoring-capacity?:base-case/disp32 + # if (curr-a->left != curr-b->left) return false + (lookup *(ecx+4) *(ecx+8)) # Type-tree-left Type-tree-left => eax + 89/<- %edx 0/r32/eax + (lookup *(ebx+4) *(ebx+8)) # Type-tree-left Type-tree-left => eax + (type-equal? %edx %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $type-equal-ignoring-capacity?:end/disp32 # eax switches meaning + # if (curr-a->left == "array") curr-a = curr-a->element-type + { + (is-mu-array? %edx) # => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 +$type-equal-ignoring-capacity?:array: + # curr-a = curr-a->right->left + (lookup *(ecx+0xc) *(ecx+0x10)) # Type-tree-right Type-tree-right => eax + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + 89/<- %ecx 0/r32/eax + # curr-b = curr-b->right->left + (lookup *(ebx+0xc) *(ebx+0x10)) # Type-tree-right Type-tree-right => eax + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + 89/<- %ebx 0/r32/eax + eb/jump $type-equal-ignoring-capacity?:base-case/disp8 + } + # if (curr-a->left == "stream") curr-a = curr-a->element-type + { + (is-mu-stream? %edx) # => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 +$type-equal-ignoring-capacity?:stream: + # curr-a = curr-a->right->left + (lookup *(ecx+0xc) *(ecx+0x10)) # Type-tree-right Type-tree-right => eax + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + 89/<- %ecx 0/r32/eax + # curr-b = curr-b->right->left + (lookup *(ebx+0xc) *(ebx+0x10)) # Type-tree-right Type-tree-right => eax + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + 89/<- %ebx 0/r32/eax + eb/jump $type-equal-ignoring-capacity?:base-case/disp8 + } +$type-equal-ignoring-capacity?:base-case: + # return type-equal?(curr-a, curr-b) + (type-equal? %ecx %ebx) # => eax +$type-equal-ignoring-capacity?:end: + # . restore registers + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +check-mu-return-stmt: # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + 57/push-edi + # var type-parameters/edx: (addr table (handle array byte) (addr type-tree) 8) + 81 5/subop/subtract %esp 0x60/imm32 + 68/push 0x60/imm32/size + 68/push 0/imm32/read + 68/push 0/imm32/write + 89/<- %edx 4/r32/esp + # var template/esi: (addr list var) = fn->outputs + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *(eax+0x10) *(eax+0x14)) # Function-outputs Function-outputs => eax + 89/<- %esi 0/r32/eax + # var curr-template/ebx: (addr list var) = fn->outputs + 89/<- %ebx 0/r32/eax + # var curr/edi: (addr stmt-var) = stmt->inouts + 8b/-> *(ebp+8) 0/r32/eax + (lookup *(eax+0xc) *(eax+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 89/<- %edi 0/r32/eax + { + # if template is null, break + 81 7/subop/compare %ebx 0/imm32 + 0f 84/jump-if-= break/disp32 + # if curr is null, abort + 81 7/subop/compare %edi 0/imm32 + 0f 84/jump-if-= $check-mu-return-stmt:error-too-few-inouts/disp32 + # var template-type/ecx: (addr type-tree) = template->value->type + (lookup *ebx *(ebx+4)) # List-value List-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + 89/<- %ecx 0/r32/eax + # var curr-type/eax: (addr type-tree) = curr->value->type + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + # if (curr->is-deref?) curr-type = payload of curr-type + 81 7/subop/compare *(edi+0x10) 0/imm32/false # Stmt-var-is-deref + { + 74/jump-if-= break/disp8 + (lookup *(eax+0xc) *(eax+0x10)) # Type-tree-right Type-tree-right => eax + # if t->right is null, t = t->left + 81 7/subop/compare *(eax+0xc) 0/imm32 # Type-tree-right + 75/jump-if-!= break/disp8 + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } + # if curr-type is literal and template-type is float, abort + 50/push-eax + { + (is-simple-mu-type? %eax 0) # literal => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (is-simple-mu-type? %ecx 0xf) # float => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $check-mu-return-stmt:error-literal-to-float/disp32 + } + 58/pop-to-eax + # if (curr-type != template-type) abort + (type-match? %ecx %eax %edx) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-return-stmt:error1/disp32 + # if register-within-list-with-conflict?(curr, original template, curr-template, stmt) abort + (register-within-list-with-conflict? %edi %esi %ebx *(ebp+8)) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $check-mu-return-stmt:error2/disp32 + # template = template->next + (lookup *(ebx+8) *(ebx+0xc)) # List-next List-next => eax + 89/<- %ebx 0/r32/eax + # curr = curr->next + (lookup *(edi+8) *(edi+0xc)) # Stmt-var-next Stmt-var-next => eax + 89/<- %edi 0/r32/eax + # + e9/jump loop/disp32 + } + # if curr is not null, abort + 81 7/subop/compare %edi 0/imm32 + 0f 85/jump-if-!= $check-mu-return-stmt:error-too-many-inouts/disp32 +$check-mu-return-stmt:end: + # . reclaim locals + 81 0/subop/add %esp 0x6c/imm32 + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$check-mu-return-stmt:error1: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": return: '") + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' has the wrong type\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-return-stmt:error2: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": return: '") + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' is no longer available\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-return-stmt:error-literal-to-float: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": return: cannot copy literal '") + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' to float\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-return-stmt:error-too-few-inouts: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": return: too few inouts\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-return-stmt:error-too-many-inouts: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": return: too many inouts\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +check-all-unique-registers: # outputs: (addr list var), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 56/push-esi + # var table/esi: (addr table (handle array byte) int 8) + 81 5/subop/subtract %esp 0x60/imm32 + 68/push 0x60/imm32/size + 68/push 0/imm32/read + 68/push 0/imm32/write + 89/<- %esi 4/r32/esp + # var curr/ecx: (addr list var) = outputs + 8b/-> *(ebp+8) 1/r32/ecx + { + # if (curr == 0) break + 81 7/subop/compare %ecx 0/imm32 + 0f 84/jump-if-= break/disp32 + # var reg/eax: (addr array byte) = curr->value->register # guaranteed to exist + (lookup *ecx *(ecx+4)) # List-value List-value => eax + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + # if reg exists in table, abort + (maybe-get %esi %eax 0xc) # => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-all-unique-registers:abort/disp32 + # insert reg in table + (lookup *ecx *(ecx+4)) # List-value List-value => eax + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + (get-or-insert %esi %eax 0xc Heap) + # curr = curr->next + (lookup *(ecx+8) *(ecx+0xc)) # List-next List-next => eax + 89/<- %ecx 0/r32/eax + e9/jump loop/disp32 + } +$check-all-unique-registers:end: + # . reclaim locals + 81 0/subop/add %esp 0x6c/imm32 + # . restore registers + 5e/pop-to-esi + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$check-all-unique-registers:abort: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": outputs must be in unique registers\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +# return false if s's register is not between start (inclusive) and end (exclusive) +# return false if the positionally corresponding register in stmt->inouts (where s comes from) is also s's register +# otherwise return true +register-within-list-with-conflict?: # s: (addr stmt-var), start: (addr list var), end: (addr list var), stmt: (addr stmt) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + 57/push-edi + # var target/ebx: (addr array byte) = s->value->register + 8b/-> *(ebp+8) 0/r32/eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax +#? (write-buffered Stderr "AA: ") +#? (write-buffered Stderr %eax) +#? (write-buffered Stderr Newline) +#? (flush Stderr) + # if (var->register == 0) return false + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $register-within-list-with-conflict?:end/disp32 # eax turns into result + 89/<- %ebx 0/r32/eax + # var curr/ecx: (addr list var) = start + 8b/-> *(ebp+0xc) 1/r32/ecx + # edx = end + 8b/-> *(ebp+0x10) 2/r32/edx + { + # if (curr == 0) break + 81 7/subop/compare %edi 0/imm32 + 0f 84/jump-if-= break/disp32 + # if (curr == end) break + 39/compare %ecx 2/r32/edx + 0f 84/jump-if-= break/disp32 + # var curr-reg/eax: (addr array byte) = curr->value->register + (lookup *ecx *(ecx+4)) # List-value List-value => eax + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + # if (curr-reg == 0) continue + 3d/compare-eax-and 0/imm32 + 74/jump-if-= $register-within-list-with-conflict?:continue/disp8 + # if (curr-reg == target) check for conflict + (string-equal? %eax %ebx) # => eax + 3d/compare-eax-and 0/imm32/false + { + 74/jump-if-= break/disp8 +#? (write-buffered Stderr "conflict?\n") +#? (flush Stderr) + # var return-inouts/eax: (addr stmt-var) = stmt->inouts + 8b/-> *(ebp+0x14) 0/r32/eax + (lookup *(eax+0xc) *(eax+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (register-conflict? %ebx %eax *(ebp+0xc)) # => eax + eb/jump $register-within-list-with-conflict?:end/disp8 + } +$register-within-list-with-conflict?:continue: + # curr = curr->next + (lookup *(ecx+8) *(ecx+0xc)) # List-next List-next => eax + 89/<- %ecx 0/r32/eax + e9/jump loop/disp32 + } + # return false + b8/copy-to-eax 0/imm32/false +$register-within-list-with-conflict?:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# At the first occurrence of register 'reg' in fn-outputs, +# check if the corresponding element of return-inouts has a different register. +# This hacky helper is intended to be called in one specific place. Don't +# reuse it as is. +register-conflict?: # reg: (addr array byte), return-inouts: (addr stmt-var), fn-outputs: (addr list var) => result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + 57/push-edi +#? (write-buffered Stderr "BB: ") +#? (write-buffered Stderr *(ebp+8)) +#? (write-buffered Stderr Newline) +#? (flush Stderr) + # var curr-output/edi: (addr list var) = fn-outputs + 8b/-> *(ebp+0x10) 7/r32/edi + # var curr-inout/esi: (addr stmt-var) = return-inouts + 8b/-> *(ebp+0xc) 6/r32/esi + { + # if (curr-output == 0) abort + 81 7/subop/compare %edi 0/imm32 + 0f 84/jump-if-= break/disp32 + # if (curr-output->value->register != reg) continue + (lookup *edi *(edi+4)) # List-value List-value => eax + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + (string-equal? %eax *(ebp+8)) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if= $register-conflict?:continue/disp32 +#? (write-buffered Stderr "rescan\n") +#? (flush Stderr) + # var curr-reg/eax: (addr array byte) = curr-inout->value->register + (lookup *esi *(esi+4)) # List-value List-value => eax + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + # if (curr-reg == 0) return true + 3d/compare-eax-and 0/imm32 + { + 75/jump-if-!= break/disp8 +#? (write-buffered Stderr "no register\n") +#? (flush Stderr) + b8/copy-to-eax 1/imm32/true + e9/jump $register-conflict?:end/disp32 + } + # return (curr-reg != reg) + (string-equal? %eax *(ebp+8)) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 94/set-if-= %al +#? (write-buffered Stderr "final: ") +#? (write-int32-hex-buffered Stderr %eax) +#? (write-buffered Stderr Newline) +#? (flush Stderr) + eb/jump $register-conflict?:end/disp8 +$register-conflict?:continue: + # curr-output = curr-output->next + (lookup *(edi+8) *(edi+0xc)) # List-next List-next => eax + 89/<- %edi 0/r32/eax + # curr-inout = curr-inout->next + (lookup *(esi+8) *(esi+0xc)) # Stmt-var-next Stmt-var-next => eax + 89/<- %esi 0/r32/eax + e9/jump loop/disp32 + } + # should never get here + (write-buffered Stderr "register-conflict? misused\n") + (flush Stderr) + e8/call syscall_exit/disp32 +$register-conflict?:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +check-final-stmt-is-return: # block: (addr block), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + # var curr/ecx: (addr list stmt) = block->stmts + 8b/-> *(ebp+8) 0/r32/eax + (lookup *(eax+4) *(eax+8)) # Block-stmts Block-stmts => eax + 3d/compare-eax-and 0/imm32 + 74/jump-if-= $check-final-stmt-is-return:error/disp8 + 89/<- %ecx 0/r32/eax + { + # if curr->next == 0, break + (lookup *(ecx+8) *(ecx+0xc)) # List-next List-next => eax + 3d/compare-eax-and 0/imm32 + 74/jump-if-= break/disp8 + # curr = curr->next + 89/<- %ecx 0/r32/eax + e9/jump loop/disp32 + } +$check-final-stmt-is-return:check-tag: + # if curr->value->tag != Stmt1, abort + (lookup *ecx *(ecx+4)) # List-value List-value => eax + 81 7/subop/compare *eax 1/imm32/stmt1 # Stmt-tag + 75/jump-if-!= $check-final-stmt-is-return:error/disp8 +$check-final-stmt-is-return:check-operation: + # if curr->operation != "return", abort + (lookup *(eax+4) *(eax+8)) # Stmt1-operation Stmt1-operation => eax + (string-equal? %eax "return") + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= $check-final-stmt-is-return:error/disp8 +$check-final-stmt-is-return:end: + # . restore registers + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$check-final-stmt-is-return:error: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": final statement should be a 'return'\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +check-no-breaks: # block: (addr block), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + # var curr/ecx: (addr list stmt) = block->stmts + 8b/-> *(ebp+8) 0/r32/eax + (lookup *(eax+4) *(eax+8)) # Block-stmts Block-stmts => eax + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-no-breaks:end/disp32 + 89/<- %ecx 0/r32/eax + { + # if curr->next == 0, break + (lookup *(ecx+8) *(ecx+0xc)) # List-next List-next => eax + 3d/compare-eax-and 0/imm32 + 74/jump-if-= break/disp8 + # if curr->value->tag != Stmt1, continue + (lookup *ecx *(ecx+4)) # List-value List-value => eax + 81 7/subop/compare *eax 1/imm32/stmt1 # Stmt-tag + 75/jump-if-!= $check-no-breaks:continue/disp8 + # if curr->value->operation starts with "break", abort + (lookup *(eax+4) *(eax+8)) # Stmt1-operation Stmt1-operation => eax + (string-starts-with? %eax "break") # => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= $check-no-breaks:error/disp8 +$check-no-breaks:continue: + # curr = curr->next + (lookup *(ecx+8) *(ecx+0xc)) # List-next List-next => eax + 89/<- %ecx 0/r32/eax + e9/jump loop/disp32 + } +$check-no-breaks:end: + # . restore registers + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$check-no-breaks:error: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) " has outputs, so you cannot 'break' out of the outermost block. Use 'return'.\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +check-mu-get-stmt: # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + 57/push-edi + # esi = stmt + 8b/-> *(ebp+8) 6/r32/esi + # - check for 0 inouts + # var base/ecx: (addr var) = stmt->inouts->value + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-get-stmt:error-too-few-inouts/disp32 + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %ecx 0/r32/eax +$check-mu-get-stmt:check-base: + # - check base type + # if it's an 'addr', check that it's in a register + # var base-type/ebx: (addr type-tree) = lookup(base->type) + (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + 89/<- %ebx 0/r32/eax + { + 81 7/subop/compare *ebx 0/imm32/false # Type-tree-is-atom + 0f 85/jump-if-!= break/disp32 +$check-mu-get-stmt:base-is-compound: + # if (type->left != addr) break + (lookup *(ebx+4) *(ebx+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 2) # addr => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 +$check-mu-get-stmt:base-is-addr: + # now check for register + 81 7/subop/compare *(ecx+0x18) 0/imm32 # Var-register + 0f 84/jump-if-= $check-mu-get-stmt:error-base-type-addr-but-not-register/disp32 +$check-mu-get-stmt:base-is-addr-in-register: + # type->left is now an addr; skip it + (lookup *(ebx+0xc) *(ebx+0x10)) # Type-tree-right Type-tree-right => eax + 81 7/subop/compare *(eax+0xc) 0/imm32 # Type-tree-right + 0f 85/jump-if-!= $check-mu-get-stmt:error-bad-base/disp32 +$check-mu-get-stmt:base-is-addr-to-atom-in-register: + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + 89/<- %ebx 0/r32/eax + } +$check-mu-get-stmt:check-base-typeinfo: + # ensure type is a container + 81 7/subop/compare *ebx 0/imm32/false # Type-tree-is-atom + { + 75/jump-if-!= break/disp8 + (lookup *(ebx+4) *(ebx+8)) # Type-tree-left Type-tree-left => eax + 89/<- %ebx 0/r32/eax + } + # var base-type-id/ebx: type-id = base-type->value + 8b/-> *(ebx+4) 3/r32/ebx # Type-tree-value + (is-container? %ebx) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-get-stmt:error-bad-base/disp32 + # var base-typeinfo/edx: (addr typeinfo) = find-typeinfo(base-type-id) + # . var container/ecx: (handle typeinfo) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %ecx 4/r32/esp + # . + (find-typeinfo %ebx %ecx) + (lookup *ecx *(ecx+4)) # => eax + # . reclaim container + 81 0/subop/add %esp 8/imm32 + # . + 89/<- %edx 0/r32/eax + # var offset/ecx: (addr stmt-var) = stmt->inouts->next + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax + 89/<- %ecx 0/r32/eax + # - check for 1 inout + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-get-stmt:error-too-few-inouts/disp32 + # var offset/ecx: (addr var) = lookup(offset->value) + (lookup *ecx *(ecx+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %ecx 0/r32/eax + # - check for valid field + 81 7/subop/compare *(ecx+0x14) -1/imm32/uninitialized # Var-offset + 0f 84/jump-if-= $check-mu-get-stmt:error-bad-field/disp32 + # - check for too many inouts + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $check-mu-get-stmt:error-too-many-inouts/disp32 + # var output/edi: (addr var) = stmt->outputs->value + (lookup *(esi+0x14) *(esi+0x18)) # Stmt1-outputs Stmt1-outputs => eax + # - check for 0 outputs + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-get-stmt:error-too-few-outputs/disp32 + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %edi 0/r32/eax +$check-mu-get-stmt:check-output-type: + # - check output type + # must be in register + (lookup *(edi+0x18) *(edi+0x1c)) # Var-register Var-register => eax + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-get-stmt:error-output-not-in-register/disp32 + # must have a non-atomic type + (lookup *(edi+8) *(edi+0xc)) # Var-type Var-type => eax + 81 7/subop/compare *eax 0/imm32/false # Type-tree-is-atom + 0f 85/jump-if-!= $check-mu-get-stmt:error-output-type-not-address/disp32 + # type must start with (addr ...) + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 2) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-get-stmt:error-output-type-not-address/disp32 +$check-mu-get-stmt:check-output-type-match: + # payload of addr type must match 'type' definition + (lookup *(edi+8) *(edi+0xc)) # Var-type Var-type => eax + (lookup *(eax+0xc) *(eax+0x10)) # Type-tree-right Type-tree-right => eax + # if (payload->right == null) payload = payload->left + 81 7/subop/compare *(eax+0xc) 0/imm32/null # Type-tree-right + { + 75/jump-if-!= break/disp8 + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } + 89/<- %edi 0/r32/eax + # . var output-name/ecx: (addr array byte) + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + 89/<- %ecx 0/r32/eax + # . var base-typeinfo-entry/eax: (addr handle typeinfo-entry) + (lookup *(edx+4) *(edx+8)) # Typeinfo-fields Typeinfo-fields => eax + (get %eax %ecx 0x10) # => eax + # . + (lookup *eax *(eax+4)) # => eax + (lookup *eax *(eax+4)) # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + # . + (type-equal? %edi %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-get-stmt:error-bad-output-type/disp32 + # - check for too many outputs + (lookup *(esi+0x14) *(esi+0x18)) # Stmt1-outputs Stmt1-outputs => eax + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $check-mu-get-stmt:error-too-many-outputs/disp32 +$check-mu-get-stmt:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$check-mu-get-stmt:error-too-few-inouts: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt get: too few inouts (2 required)\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-get-stmt:error-too-many-inouts: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt get: too many inouts (2 required)\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-get-stmt:error-too-few-outputs: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt get: must have an output\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-get-stmt:error-too-many-outputs: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt get: too many outputs (1 required)\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-get-stmt:error-bad-base: + # error("fn " fn ": stmt get: var '" base->name "' must have a 'type' definition\n") + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt get: var '") + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' must have a 'type' definition\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-get-stmt:error-base-type-addr-but-not-register: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt get: var '") + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' is an 'addr' type, and so must live in a register\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-get-stmt:error-bad-field: + # error("fn " fn ": stmt get: type " type " has no member called '" curr->name "'\n") + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt get: type '") + # . write(Type-id->data[tmp]) + bf/copy-to-edi Type-id/imm32 + 8b/-> *(edi+ebx<<2+0xc) 6/r32/esi + { + 81 7/subop/compare %esi 0/imm32 + 74/jump-if-= break/disp8 + (write-buffered *(ebp+0x10) %esi) + } + # . + (write-buffered *(ebp+0x10) "' has no member called '") + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "'\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-get-stmt:error-output-not-in-register: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt get: output '") + (lookup *edi *(edi+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' is not in a register\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-get-stmt:error-output-type-not-address: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt get: output must be an addr\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-get-stmt:error-bad-output-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt get: wrong output type for member '") + (write-buffered *(ebp+0x10) %ecx) + (write-buffered *(ebp+0x10) "' of type '") + bf/copy-to-edi Type-id/imm32 + 8b/-> *(edi+ebx<<2+0xc) 6/r32/esi + { + 81 7/subop/compare %esi 0/imm32 + 74/jump-if-= break/disp8 + (write-buffered *(ebp+0x10) %esi) + } + (write-buffered *(ebp+0x10) "'\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +check-mu-index-stmt: # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + 57/push-edi + # esi = stmt + 8b/-> *(ebp+8) 6/r32/esi + # - check for 0 inouts + # var base/ecx: (addr var) = stmt->inouts->value + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax +$check-mu-index-stmt:check-no-inouts: + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-index-stmt:error-too-few-inouts/disp32 + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %ecx 0/r32/eax + # - check base type is either (addr array ...) in register or (array ...) on stack + # var base-type/ebx: (addr type-tree) = lookup(base->type) + (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + 89/<- %ebx 0/r32/eax + # if base-type is an atom, abort with a precise error + 81 7/subop/compare *ebx 0/imm32/false # Type-tree-is-atom + { + 74/jump-if-= break/disp8 + (is-simple-mu-type? %ebx 3) # array => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $check-mu-index-stmt:error-base-array-atom-type/disp32 + 0f 84/jump-if-= $check-mu-index-stmt:error-base-non-array-type/disp32 + } +$check-mu-index-stmt:base-is-compound: + # if type->left not addr or array, abort + { + (lookup *(ebx+4) *(ebx+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 2) # addr => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 + (lookup *(ebx+4) *(ebx+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 3) # array => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 + e9/jump $check-mu-index-stmt:error-base-non-array-type/disp32 + } + # if (type->left == addr) ensure type->right->left == array and type->register exists + { + (lookup *(ebx+4) *(ebx+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 2) # addr => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 +$check-mu-index-stmt:base-is-addr: + (lookup *(ebx+0xc) *(ebx+0x10)) # Type-tree-right Type-tree-right => eax + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 3) # array => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-index-stmt:error-base-non-array-type/disp32 +$check-mu-index-stmt:check-base-addr-is-register: + 81 7/subop/compare *(ecx+0x18) 0/imm32 # Var-register + 0f 84/jump-if-= $check-mu-index-stmt:error-base-address-array-type-on-stack/disp32 + } + # if (type->left == array) ensure type->register doesn't exist + { + (lookup *(ebx+4) *(ebx+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 3) # array => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 +$check-mu-index-stmt:base-is-array: + 81 7/subop/compare *(ecx+0x18) 0/imm32 # Var-register + 0f 85/jump-if-!= $check-mu-index-stmt:error-base-array-type-in-register/disp32 + } + # if (base-type->left == addr) base-type = base-type->right + { + (lookup *(ebx+4) *(ebx+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 2) # addr => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (lookup *(ebx+0xc) *(ebx+0x10)) # Type-tree-right Type-tree-right => eax + 89/<- %ebx 0/r32/eax + } + # - check for 1 inout + # var index/ecx: (addr stmt-var) = stmt->inouts->next->value + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax +$check-mu-index-stmt:check-single-inout: + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-index-stmt:error-too-few-inouts/disp32 + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %ecx 0/r32/eax + # - check index is either a literal or register + # var index-type/edx: (addr type-tree) + (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + 89/<- %edx 0/r32/eax + # if index type is an atom, it must be a literal or int + 81 7/subop/compare *edx 0/imm32/false # Type-tree-is-atom + { + 74/jump-if-= break/disp8 +$check-mu-index-stmt:index-type-is-atom: + (is-simple-mu-type? %edx 0) # literal => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= $check-mu-index-stmt:index-type-done/disp8 + (is-simple-mu-type? %edx 1) # int => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= $check-mu-index-stmt:index-type-done/disp8 + (is-simple-mu-type? %edx 7) # offset => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $check-mu-index-stmt:error-index-offset-atom-type/disp32 + e9/jump $check-mu-index-stmt:error-invalid-index-type/disp32 + } + # if index type is a non-atom: it must be an offset + { + 75/jump-if-!= break/disp8 +$check-mu-index-stmt:index-type-is-non-atom: + (lookup *(edx+4) *(edx+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 7) # offset => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-index-stmt:error-invalid-index-type/disp32 + } +$check-mu-index-stmt:index-type-done: + # check index is either a literal or in a register + { + (is-simple-mu-type? %edx 0) # literal => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 +$check-mu-index-stmt:check-index-in-register: + 81 7/subop/compare *(ecx+0x18) 0/imm32 # Var-register + 0f 84/jump-if-= $check-mu-index-stmt:error-index-on-stack/disp32 + } + # - if index is an 'int', check that element type of base has size 1, 2, 4 or 8 bytes. + { + (is-simple-mu-type? %edx 1) # int => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 +$check-mu-index-stmt:check-index-can-be-int: + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + (array-element-size %eax) # => eax + 3d/compare-eax-and 1/imm32 + 74/jump-if-= break/disp8 + 3d/compare-eax-and 2/imm32 + 74/jump-if-= break/disp8 + 3d/compare-eax-and 4/imm32 + 74/jump-if-= break/disp8 + 3d/compare-eax-and 8/imm32 + 74/jump-if-= break/disp8 + e9/jump $check-mu-index-stmt:error-index-needs-offset/disp32 + } + # - check for too many inouts + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $check-mu-index-stmt:error-too-many-inouts/disp32 + # - check for 0 outputs + # var output/edi: (addr var) = stmt->outputs->value + (lookup *(esi+0x14) *(esi+0x18)) # Stmt1-outputs Stmt1-outputs => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-index-stmt:error-too-few-outputs/disp32 + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %edi 0/r32/eax + # - check output type + # must have a non-atomic type + (lookup *(edi+8) *(edi+0xc)) # Var-type Var-type => eax + 89/<- %edx 0/r32/eax + 81 7/subop/compare *edx 0/imm32/false # Type-tree-is-atom + 0f 85/jump-if-!= $check-mu-index-stmt:error-output-type-not-address/disp32 + # type must start with (addr ...) + (lookup *(edx+4) *(edx+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 2) # addr => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-index-stmt:error-output-type-not-address/disp32 + # if tail(base-type) != tail(output-type) abort + (type-tail %ebx) # => eax + 89/<- %ebx 0/r32/eax + (type-tail %edx) # => eax + (type-equal? %ebx %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-index-stmt:error-bad-output-type/disp32 + # - check for too many outputs + (lookup *(esi+0x14) *(esi+0x18)) # Stmt1-outputs Stmt1-outputs => eax + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $check-mu-index-stmt:error-too-many-outputs/disp32 +$check-mu-index-stmt:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$check-mu-index-stmt:error-base-non-array-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt index: var '") + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' is not an array\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-index-stmt:error-base-array-atom-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt index: array '") + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' must specify the type of its elements\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-index-stmt:error-base-address-array-type-on-stack: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt index: var '") + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' is an addr to an array, and so must live in a register\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-index-stmt:error-base-array-type-in-register: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt index: var '") + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' is an array, and so must live on the stack\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-index-stmt:error-too-few-inouts: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt index: too few inouts (2 required)\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-index-stmt:error-invalid-index-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt index: second argument '") + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' must be an int or offset\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-index-stmt:error-index-offset-atom-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt index: offset '") + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' must specify the type of array elements\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-index-stmt:error-index-on-stack: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt index: second argument '") + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' must be in a register\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-index-stmt:error-index-needs-offset: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt index: cannot take an int for array '") + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "'; create an offset instead. See mu.md for details.\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-index-stmt:error-too-many-inouts: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt index: too many inouts (2 required)\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-index-stmt:error-too-few-outputs: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt index: must have an output\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-index-stmt:error-too-many-outputs: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt index: too many outputs (1 required)\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-index-stmt:error-output-not-in-register: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt index: output '") + (lookup *edi *(edi+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' is not in a register\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-index-stmt:error-output-type-not-address: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt index: output '") + (lookup *edi *(edi+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' must be an addr\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-index-stmt:error-bad-output-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt index: output '") + (lookup *edi *(edi+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' does not have the right type\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +check-mu-length-stmt: # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + 57/push-edi + # esi = stmt + 8b/-> *(ebp+8) 6/r32/esi + # - check for 0 inouts + # var base/ecx: (addr var) = stmt->inouts->value + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax +$check-mu-length-stmt:check-no-inouts: + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-length-stmt:error-too-few-inouts/disp32 + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %ecx 0/r32/eax + # - check base type is either (addr array ...) in register or (array ...) on stack + # var base-type/ebx: (addr type-tree) = lookup(base->type) + (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + 89/<- %ebx 0/r32/eax + # if base-type is an atom, abort with a precise error + 81 7/subop/compare *ebx 0/imm32/false # Type-tree-is-atom + { + 74/jump-if-= break/disp8 + (is-simple-mu-type? %ebx 3) # array => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $check-mu-length-stmt:error-base-array-atom-type/disp32 + 0f 84/jump-if-= $check-mu-length-stmt:error-base-non-array-type/disp32 + } +$check-mu-length-stmt:base-is-compound: + # if type->left not addr or array, abort + { + (lookup *(ebx+4) *(ebx+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 2) # addr => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 + (lookup *(ebx+4) *(ebx+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 3) # array => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 + e9/jump $check-mu-length-stmt:error-base-non-array-type/disp32 + } + # if (type->left == addr) ensure type->right->left == array and type->register exists + { + (lookup *(ebx+4) *(ebx+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 2) # addr => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 +$check-mu-length-stmt:base-is-addr: + (lookup *(ebx+0xc) *(ebx+0x10)) # Type-tree-right Type-tree-right => eax + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 3) # array => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-length-stmt:error-base-non-array-type/disp32 +$check-mu-length-stmt:check-base-addr-is-register: + 81 7/subop/compare *(ecx+0x18) 0/imm32 # Var-register + 0f 84/jump-if-= $check-mu-length-stmt:error-base-address-array-type-on-stack/disp32 + } + # if (type->left == array) ensure type->register doesn't exist + { + (lookup *(ebx+4) *(ebx+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 3) # array => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 +$check-mu-length-stmt:base-is-array: + 81 7/subop/compare *(ecx+0x18) 0/imm32 # Var-register + 0f 85/jump-if-!= $check-mu-length-stmt:error-base-array-type-in-register/disp32 + } + # if (base-type->left == addr) base-type = base-type->right + { + (lookup *(ebx+4) *(ebx+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 2) # addr => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (lookup *(ebx+0xc) *(ebx+0x10)) # Type-tree-right Type-tree-right => eax + 89/<- %ebx 0/r32/eax + } + # - check for too many inouts + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $check-mu-length-stmt:error-too-many-inouts/disp32 + # - check for 0 outputs + # var output/edi: (addr var) = stmt->outputs->value + (lookup *(esi+0x14) *(esi+0x18)) # Stmt1-outputs Stmt1-outputs => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-length-stmt:error-too-few-outputs/disp32 + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %edi 0/r32/eax + # - check output type + # must have a non-atomic type + (lookup *(edi+8) *(edi+0xc)) # Var-type Var-type => eax + (is-simple-mu-type? %eax 1) # int => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-length-stmt:error-invalid-output-type/disp32 + # - check for too many outputs + (lookup *(esi+0x14) *(esi+0x18)) # Stmt1-outputs Stmt1-outputs => eax + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $check-mu-length-stmt:error-too-many-outputs/disp32 +$check-mu-length-stmt:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$check-mu-length-stmt:error-base-non-array-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt length: var '") + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' is not an array\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-length-stmt:error-base-array-atom-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt length: array '") + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' must specify the type of its elements\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-length-stmt:error-base-address-array-type-on-stack: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt length: var '") + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' is an addr to an array, and so must live in a register\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-length-stmt:error-base-array-type-in-register: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt length: var '") + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' is an array, and so must live on the stack\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-length-stmt:error-too-few-inouts: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt length: too few inouts (1 required)\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-length-stmt:error-invalid-index-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt length: second argument '") + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' must be an int or offset\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-length-stmt:error-index-offset-atom-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt length: offset '") + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' must specify the type of array elements\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-length-stmt:error-index-on-stack: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt length: second argument '") + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' must be in a register\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-length-stmt:error-index-needs-offset: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt length: cannot take an int for array '") + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "'; create an offset instead. See mu.md for details.\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-length-stmt:error-too-many-inouts: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt length: too many inouts (1 required)\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-length-stmt:error-too-few-outputs: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt length: must have an output\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-length-stmt:error-too-many-outputs: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt length: too many outputs (1 required)\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-length-stmt:error-output-not-in-register: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt length: output '") + (lookup *edi *(edi+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' is not in a register\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-length-stmt:error-invalid-output-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt length: output '") + (lookup *edi *(edi+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' does not have the right type\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +check-mu-compute-offset-stmt: # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + 57/push-edi + # esi = stmt + 8b/-> *(ebp+8) 6/r32/esi + # - check for 0 inouts + # var base/ecx: (addr var) = stmt->inouts->value + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax +$check-mu-compute-offset-stmt:check-no-inouts: + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-compute-offset-stmt:error-too-few-inouts/disp32 + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %ecx 0/r32/eax + # - check base type is either (addr array ...) in register or (array ...) on stack + # var base-type/ebx: (addr type-tree) = lookup(base->type) + (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + 89/<- %ebx 0/r32/eax + # if base-type is an atom, abort with a precise error + 81 7/subop/compare *ebx 0/imm32/false # Type-tree-is-atom + { + 74/jump-if-= break/disp8 + (is-simple-mu-type? %ebx 3) # array => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $check-mu-compute-offset-stmt:error-base-array-atom-type/disp32 + 0f 84/jump-if-= $check-mu-compute-offset-stmt:error-base-non-array-type/disp32 + } +$check-mu-compute-offset-stmt:base-is-compound: + # if type->left not addr or array, abort + { + (lookup *(ebx+4) *(ebx+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 2) # addr => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 + (lookup *(ebx+4) *(ebx+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 3) # array => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 + e9/jump $check-mu-compute-offset-stmt:error-base-non-array-type/disp32 + } + # if (type->left == addr) ensure type->right->left == array and type->register exists + { + (lookup *(ebx+4) *(ebx+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 2) # addr => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 +$check-mu-compute-offset-stmt:base-is-addr: + (lookup *(ebx+0xc) *(ebx+0x10)) # Type-tree-right Type-tree-right => eax + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 3) # array => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-compute-offset-stmt:error-base-non-array-type/disp32 + } + # if (base-type->left == addr) base-type = base-type->right + { + (lookup *(ebx+4) *(ebx+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 2) # addr => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (lookup *(ebx+0xc) *(ebx+0x10)) # Type-tree-right Type-tree-right => eax + 89/<- %ebx 0/r32/eax + } + # - check for 1 inout + # var index/ecx: (addr stmt-var) = stmt->inouts->next->value + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax +$check-mu-compute-offset-stmt:check-single-inout: + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-compute-offset-stmt:error-too-few-inouts/disp32 + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %ecx 0/r32/eax + # - check index is either a literal or register + # var index-type/edx: (addr type-tree) + (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + 89/<- %edx 0/r32/eax + # index type must be a literal or int + 81 7/subop/compare *edx 0/imm32/false # Type-tree-is-atom + 0f 84/jump-if-= $check-mu-compute-offset-stmt:error-invalid-index-type/disp32 + { +$check-mu-compute-offset-stmt:index-type-is-atom: + (is-simple-mu-type? %edx 0) # literal => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 + (is-simple-mu-type? %edx 1) # int => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 + e9/jump $check-mu-compute-offset-stmt:error-invalid-index-type/disp32 + } + # - check for too many inouts + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $check-mu-compute-offset-stmt:error-too-many-inouts/disp32 + # - check for 0 outputs + # var output/edi: (addr var) = stmt->outputs->value + (lookup *(esi+0x14) *(esi+0x18)) # Stmt1-outputs Stmt1-outputs => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-compute-offset-stmt:error-too-few-outputs/disp32 + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %edi 0/r32/eax + # - check output type + # must have a non-atomic type + (lookup *(edi+8) *(edi+0xc)) # Var-type Var-type => eax + 89/<- %edx 0/r32/eax + 81 7/subop/compare *edx 0/imm32/false # Type-tree-is-atom + 0f 85/jump-if-!= $check-mu-compute-offset-stmt:error-output-type-not-offset/disp32 + # type must start with (offset ...) + (lookup *(edx+4) *(edx+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 7) # offset => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-compute-offset-stmt:error-output-type-not-offset/disp32 + # if tail(base-type) != tail(output-type) abort + (type-tail %ebx) # => eax + 89/<- %ebx 0/r32/eax + (type-tail %edx) # => eax + (type-equal? %ebx %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-compute-offset-stmt:error-bad-output-type/disp32 + # - check for too many outputs + (lookup *(esi+0x14) *(esi+0x18)) # Stmt1-outputs Stmt1-outputs => eax + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $check-mu-compute-offset-stmt:error-too-many-outputs/disp32 +$check-mu-compute-offset-stmt:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$check-mu-compute-offset-stmt:error-base-non-array-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt compute-offset: var '") + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' is not an array\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-compute-offset-stmt:error-base-array-atom-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt compute-offset: array '") + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' must specify the type of its elements\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-compute-offset-stmt:error-too-few-inouts: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt compute-offset: too few inouts (2 required)\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-compute-offset-stmt:error-invalid-index-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt compute-offset: second argument '") + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' must be an int\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-compute-offset-stmt:error-index-offset-atom-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt compute-offset: offset '") + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' must specify the type of array elements\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-compute-offset-stmt:error-index-on-stack: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt compute-offset: second argument '") + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' must be in a register\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-compute-offset-stmt:error-too-many-inouts: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt compute-offset: too many inouts (2 required)\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-compute-offset-stmt:error-too-few-outputs: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt compute-offset: must have an output\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-compute-offset-stmt:error-too-many-outputs: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt compute-offset: too many outputs (1 required)\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-compute-offset-stmt:error-output-not-in-register: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt compute-offset: output '") + (lookup *edi *(edi+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' is not in a register\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-compute-offset-stmt:error-output-type-not-offset: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt compute-offset: output '") + (lookup *edi *(edi+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' must be an offset\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-compute-offset-stmt:error-bad-output-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt compute-offset: output '") + (lookup *edi *(edi+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' does not have the right type\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +check-mu-copy-object-stmt: # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 53/push-ebx + 56/push-esi + 57/push-edi + # esi = stmt + 8b/-> *(ebp+8) 6/r32/esi +$check-mu-copy-object-stmt:check-for-output: + # if stmt->outputs abort + (lookup *(esi+0x14) *(esi+0x18)) # Stmt1-outputs Stmt1-outputs => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-mu-copy-object-stmt:error-too-many-outputs/disp32 +$check-mu-copy-object-stmt:get-left: + # var dest/edi: (addr stmt-var) = stmt->inouts + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 89/<- %edi 0/r32/eax + # zero inouts + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-copy-object-stmt:error-incorrect-inouts/disp32 +$check-mu-copy-object-stmt:get-src: + # var src/esi: (addr stmt-var) = dest->next + (lookup *(edi+8) *(edi+0xc)) # Stmt-var-next Stmt-var-next => eax + 89/<- %esi 0/r32/eax + # 1 inout + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-copy-object-stmt:error-incorrect-inouts/disp32 + # > 2 inouts + (lookup *(esi+8) *(esi+0xc)) # Stmt-var-next Stmt-var-next => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-mu-copy-object-stmt:error-incorrect-inouts/disp32 +$check-mu-copy-object-stmt:types: + # var src-type/ecx: (addr type-tree) = src->value->type + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + 89/<- %ecx 0/r32/eax + # if (src->is-deref?) src-type = src-type->payload + 8b/-> *(esi+0x10) 0/r32/eax # Stmt-var-is-deref + 3d/compare-eax-and 0/imm32/false + { + 74/jump-if-= break/disp8 + (lookup *(ecx+0xc) *(ecx+0x10)) # Type-tree-right Type-tree-right => eax + # if src-type->right is null, src-type = src-type->left + 81 7/subop/compare *(eax+0xc) 0/imm32 # Type-tree-right + { + 75/jump-if-!= break/disp8 + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } + 89/<- %ecx 0/r32/eax + } + # if src-type is not addr, abort + (is-mu-addr-type? %ecx) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-copy-object-stmt:error-invalid-types/disp32 + # var dest-type/ebx: (addr type-tree) = dest->value->type + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + 89/<- %ebx 0/r32/eax + # if (dest->is-deref?) dest-type = dest-type->payload + 8b/-> *(edi+0x10) 0/r32/eax # Stmt-var-is-deref + 3d/compare-eax-and 0/imm32/false + { + 74/jump-if-= break/disp8 + (lookup *(ebx+0xc) *(ebx+0x10)) # Type-tree-right Type-tree-right => eax + # if dest-type->right is null, dest-type = dest-type->left + 81 7/subop/compare *(eax+0xc) 0/imm32 # Type-tree-right + { + 75/jump-if-!= break/disp8 + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } + 89/<- %ebx 0/r32/eax + } + # if (dest-type != src-type) abort + (type-equal? %ecx %ebx) # => eax + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-copy-object-stmt:error-invalid-types/disp32 +$check-mu-copy-object-stmt:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$check-mu-copy-object-stmt:error-incorrect-inouts: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'copy-object' must have two inouts\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-copy-object-stmt:error-too-many-outputs: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'copy-object' must not have any outputs\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-copy-object-stmt:error-invalid-types: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt copy-object: two inouts with identical addr types expected\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +check-mu-clear-object-stmt: # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 53/push-ebx + 56/push-esi + 57/push-edi + # esi = stmt + 8b/-> *(ebp+8) 6/r32/esi +$check-mu-clear-object-stmt:check-for-output: + # if stmt->outputs abort + (lookup *(esi+0x14) *(esi+0x18)) # Stmt1-outputs Stmt1-outputs => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-mu-clear-object-stmt:error-too-many-outputs/disp32 +$check-mu-clear-object-stmt:get-left: + # var dest/edi: (addr stmt-var) = stmt->inouts + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 89/<- %edi 0/r32/eax + # zero inouts + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-clear-object-stmt:error-incorrect-inouts/disp32 +$check-mu-clear-object-stmt:get-src: + # > 1 inout + (lookup *(edi+8) *(edi+0xc)) # Stmt-var-next Stmt-var-next => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-mu-clear-object-stmt:error-incorrect-inouts/disp32 +$check-mu-clear-object-stmt:types: + # var src-type/ecx: (addr type-tree) = src->value->type + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + 89/<- %ecx 0/r32/eax + # if (src->is-deref?) src-type = src-type->payload + 8b/-> *(edi+0x10) 0/r32/eax # Stmt-var-is-deref + 3d/compare-eax-and 0/imm32/false + { + 74/jump-if-= break/disp8 + (lookup *(ecx+0xc) *(ecx+0x10)) # Type-tree-right Type-tree-right => eax + # if src-type->right is null, src-type = src-type->left + 81 7/subop/compare *(eax+0xc) 0/imm32 # Type-tree-right + { + 75/jump-if-!= break/disp8 + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } + 89/<- %ecx 0/r32/eax + } + # if src-type is not addr, abort + (is-mu-addr-type? %ecx) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-clear-object-stmt:error-invalid-type/disp32 +$check-mu-clear-object-stmt:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$check-mu-clear-object-stmt:error-incorrect-inouts: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'clear-object' must have a single inout\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-clear-object-stmt:error-too-many-outputs: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'clear-object' must not have any outputs\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-clear-object-stmt:error-invalid-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt clear-object: inout must have an addr type\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +check-mu-allocate-stmt: # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 53/push-ebx + 56/push-esi + 57/push-edi + # esi = stmt + 8b/-> *(ebp+8) 6/r32/esi +$check-mu-allocate-stmt:check-for-output: + # if stmt->outputs abort + (lookup *(esi+0x14) *(esi+0x18)) # Stmt1-outputs Stmt1-outputs => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-mu-allocate-stmt:error-too-many-outputs/disp32 +$check-mu-allocate-stmt:get-target: + # var target/edi: (addr stmt-var) = stmt->inouts + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 89/<- %edi 0/r32/eax + # zero inouts + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-allocate-stmt:error-incorrect-inouts/disp32 + # > 1 inouts + (lookup *(edi+8) *(edi+0xc)) # Stmt-var-next Stmt-var-next => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-mu-allocate-stmt:error-incorrect-inouts/disp32 +$check-mu-allocate-stmt:check-type: + # var target-type/ebx: (addr type-tree) = target->value->type + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + 89/<- %ebx 0/r32/eax + # if (target->is-deref?) target-type = target-type->payload + 8b/-> *(edi+0x10) 0/r32/eax # Stmt-var-is-deref + 3d/compare-eax-and 0/imm32/false + { + 74/jump-if-= break/disp8 + (lookup *(ebx+0xc) *(ebx+0x10)) # Type-tree-right Type-tree-right => eax + # if target-type->right is null, target-type = target-type->left + 81 7/subop/compare *(eax+0xc) 0/imm32 # Type-tree-right + { + 75/jump-if-!= break/disp8 + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } + 89/<- %ebx 0/r32/eax + } + # if target-type is not addr, abort + (is-mu-addr-type? %ebx) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-allocate-stmt:error-invalid-type/disp32 + # if target-type->right is an atom, abort + (lookup *(ebx+0xc) *(ebx+0x10)) # Type-tree-right Type-tree-right => eax + 81 7/subop/compare *eax 0/imm32/false # Type-tree-is-atom + 0f 85/jump-if-!= $check-mu-allocate-stmt:error-invalid-type/disp32 + # if target-type->right->left is not handle, abort + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 4) # handle => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-allocate-stmt:error-invalid-type/disp32 +$check-mu-allocate-stmt:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$check-mu-allocate-stmt:error-incorrect-inouts: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'allocate' must have a single inout\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-allocate-stmt:error-too-many-outputs: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'allocate' must not have any outputs\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-allocate-stmt:error-invalid-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt allocate: inout '") + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' must have type (addr handle ...)\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +check-mu-populate-stmt: # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 53/push-ebx + 56/push-esi + 57/push-edi + # esi = stmt + 8b/-> *(ebp+8) 6/r32/esi +$check-mu-populate-stmt:check-for-output: + # if stmt->outputs abort + (lookup *(esi+0x14) *(esi+0x18)) # Stmt1-outputs Stmt1-outputs => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-mu-populate-stmt:error-too-many-outputs/disp32 +$check-mu-populate-stmt:get-target: + # var target/edi: (addr stmt-var) = stmt->inouts + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 89/<- %edi 0/r32/eax + # zero inouts + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-populate-stmt:error-incorrect-inouts/disp32 +$check-mu-populate-stmt:get-length: + # var length/esi: (addr stmt-var) = dest->next + (lookup *(edi+8) *(edi+0xc)) # Stmt-var-next Stmt-var-next => eax + 89/<- %esi 0/r32/eax + # 1 inout + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-populate-stmt:error-incorrect-inouts/disp32 + # > 2 inouts + (lookup *(esi+8) *(esi+0xc)) # Stmt-var-next Stmt-var-next => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-mu-populate-stmt:error-incorrect-inouts/disp32 +$check-mu-populate-stmt:check-target-type: + # var target-type/ebx: (addr type-tree) = target->value->type + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + 89/<- %ebx 0/r32/eax +$check-mu-populate-stmt:check-target-type-deref: + # if (target->is-deref?) target-type = target-type->payload + 8b/-> *(edi+0x10) 0/r32/eax # Stmt-var-is-deref + 3d/compare-eax-and 0/imm32/false + { + 74/jump-if-= break/disp8 + (lookup *(ebx+0xc) *(ebx+0x10)) # Type-tree-right Type-tree-right => eax + # if target-type->right is null, target-type = target-type->left + 81 7/subop/compare *(eax+0xc) 0/imm32 # Type-tree-right + { + 75/jump-if-!= break/disp8 + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } + 89/<- %ebx 0/r32/eax + } +$check-mu-populate-stmt:check-target-type-addr: + # if target-type is not addr, abort + (is-mu-addr-type? %ebx) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-populate-stmt:error-invalid-target-type/disp32 + # if target-type->right is an atom, abort + (lookup *(ebx+0xc) *(ebx+0x10)) # Type-tree-right Type-tree-right => eax + 89/<- %ebx 0/r32/eax + 81 7/subop/compare *ebx 0/imm32/false # Type-tree-is-atom + 0f 85/jump-if-!= $check-mu-populate-stmt:error-invalid-target-type/disp32 +$check-mu-populate-stmt:check-target-type-handle: + # if target-type->right->left is not handle, abort + (lookup *(ebx+4) *(ebx+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 4) # handle => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-populate-stmt:error-invalid-target-type/disp32 + # if target-type->right->right is an atom, abort + (lookup *(ebx+0xc) *(ebx+0x10)) # Type-tree-right Type-tree-right => eax + 89/<- %ebx 0/r32/eax + 81 7/subop/compare *ebx 0/imm32/false # Type-tree-is-atom + 0f 85/jump-if-!= $check-mu-populate-stmt:error-invalid-target-type/disp32 +$check-mu-populate-stmt:check-target-type-array: + # if target-type->right->right->left is not array, abort + (lookup *(ebx+4) *(ebx+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 3) # array => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-populate-stmt:error-invalid-target-type/disp32 +$check-mu-populate-stmt:check-length-type: + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + 89/<- %ebx 0/r32/eax + (is-simple-mu-type? %ebx 0) # literal => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= $check-mu-populate-stmt:end/disp8 + (is-simple-mu-type? %ebx 1) # int => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-populate-stmt:error-invalid-length-type/disp32 +$check-mu-populate-stmt:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$check-mu-populate-stmt:error-incorrect-inouts: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'populate' must have two inouts\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-populate-stmt:error-too-many-outputs: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'populate' must not have any outputs\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-populate-stmt:error-invalid-target-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt populate: first inout '") + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' must have type (addr handle array ...)\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-populate-stmt:error-invalid-length-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt populate: second inout '") + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' must be an int\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +check-mu-populate-stream-stmt: # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 53/push-ebx + 56/push-esi + 57/push-edi + # esi = stmt + 8b/-> *(ebp+8) 6/r32/esi +$check-mu-populate-stream-stmt:check-for-output: + # if stmt->outputs abort + (lookup *(esi+0x14) *(esi+0x18)) # Stmt1-outputs Stmt1-outputs => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-mu-populate-stream-stmt:error-too-many-outputs/disp32 +$check-mu-populate-stream-stmt:get-target: + # var target/edi: (addr stmt-var) = stmt->inouts + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 89/<- %edi 0/r32/eax + # zero inouts + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-populate-stream-stmt:error-incorrect-inouts/disp32 +$check-mu-populate-stream-stmt:get-length: + # var length/esi: (addr stmt-var) = dest->next + (lookup *(edi+8) *(edi+0xc)) # Stmt-var-next Stmt-var-next => eax + 89/<- %esi 0/r32/eax + # 1 inout + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-populate-stream-stmt:error-incorrect-inouts/disp32 + # > 2 inouts + (lookup *(esi+8) *(esi+0xc)) # Stmt-var-next Stmt-var-next => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-mu-populate-stream-stmt:error-incorrect-inouts/disp32 +$check-mu-populate-stream-stmt:check-target-type: + # var target-type/ebx: (addr type-tree) = target->value->type + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + 89/<- %ebx 0/r32/eax +$check-mu-populate-stream-stmt:check-target-type-deref: + # if (target->is-deref?) target-type = target-type->payload + 8b/-> *(edi+0x10) 0/r32/eax # Stmt-var-is-deref + 3d/compare-eax-and 0/imm32/false + { + 74/jump-if-= break/disp8 + (lookup *(ebx+0xc) *(ebx+0x10)) # Type-tree-right Type-tree-right => eax + # if target-type->right is null, target-type = target-type->left + 81 7/subop/compare *(eax+0xc) 0/imm32 # Type-tree-right + { + 75/jump-if-!= break/disp8 + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } + 89/<- %ebx 0/r32/eax + } +$check-mu-populate-stream-stmt:check-target-type-addr: + # if target-type is not addr, abort + (is-mu-addr-type? %ebx) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-populate-stream-stmt:error-invalid-target-type/disp32 + # if target-type->right is an atom, abort + (lookup *(ebx+0xc) *(ebx+0x10)) # Type-tree-right Type-tree-right => eax + 89/<- %ebx 0/r32/eax + 81 7/subop/compare *ebx 0/imm32/false # Type-tree-is-atom + 0f 85/jump-if-!= $check-mu-populate-stream-stmt:error-invalid-target-type/disp32 +$check-mu-populate-stream-stmt:check-target-type-handle: + # if target-type->right->left is not handle, abort + (lookup *(ebx+4) *(ebx+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 4) # handle => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-populate-stream-stmt:error-invalid-target-type/disp32 + # if target-type->right->right is an atom, abort + (lookup *(ebx+0xc) *(ebx+0x10)) # Type-tree-right Type-tree-right => eax + 89/<- %ebx 0/r32/eax + 81 7/subop/compare *ebx 0/imm32/false # Type-tree-is-atom + 0f 85/jump-if-!= $check-mu-populate-stream-stmt:error-invalid-target-type/disp32 +$check-mu-populate-stream-stmt:check-target-type-stream: + # if target-type->right->right->left is not stream, abort + (lookup *(ebx+4) *(ebx+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 0xb) # stream => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-populate-stream-stmt:error-invalid-target-type/disp32 +$check-mu-populate-stream-stmt:check-length-type: + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + 89/<- %ebx 0/r32/eax + (is-simple-mu-type? %ebx 0) # literal => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= $check-mu-populate-stream-stmt:end/disp8 + (is-simple-mu-type? %ebx 1) # int => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-populate-stream-stmt:error-invalid-length-type/disp32 +$check-mu-populate-stream-stmt:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$check-mu-populate-stream-stmt:error-incorrect-inouts: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'populate-stream' must have two inouts\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-populate-stream-stmt:error-too-many-outputs: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'populate-stream' must not have any outputs\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-populate-stream-stmt:error-invalid-target-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt populate-stream: first inout '") + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' must have type (addr handle stream ...)\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-populate-stream-stmt:error-invalid-length-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt populate-stream: second inout '") + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' must be an int\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +check-mu-read-from-stream-stmt: # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + 57/push-edi + # esi = stmt + 8b/-> *(ebp+8) 6/r32/esi + # - check for 0 inouts + # var base/ecx: (addr var) = stmt->inouts->value + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax +$check-mu-read-from-stream-stmt:check-no-inouts: + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-read-from-stream-stmt:error-too-few-inouts/disp32 + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %ecx 0/r32/eax + # - check base type is (addr stream T) + # var base-type/ebx: (addr type-tree) = lookup(base->type) + (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + 89/<- %ebx 0/r32/eax +$check-mu-read-from-stream-stmt:check-base-is-compound: + # if base-type is an atom, abort + 81 7/subop/compare *ebx 0/imm32/false # Type-tree-is-atom + 0f 85/jump-if-!= $check-mu-read-from-stream-stmt:error-invalid-base-type/disp32 +$check-mu-read-from-stream-stmt:check-base-is-addr: + # if type->left not addr, abort + (lookup *(ebx+4) *(ebx+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 2) # addr => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-read-from-stream-stmt:error-invalid-base-type/disp32 +$check-mu-read-from-stream-stmt:check-base-is-addr-to-stream: + # base-type = base-type->right + (lookup *(ebx+0xc) *(ebx+0x10)) # Type-tree-right Type-tree-right => eax + 89/<- %ebx 0/r32/eax + # ensure base-type->left == stream + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 0xb) # stream => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-read-from-stream-stmt:error-invalid-base-type/disp32 + # - check target type is (addr T) + # var target/ecx: (addr stmt-var) = stmt->inouts->next->value + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax +$check-mu-read-from-stream-stmt:check-single-inout: + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-read-from-stream-stmt:error-too-few-inouts/disp32 + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %ecx 0/r32/eax + # var target-type/edx: (addr type-tree) + (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + 89/<- %edx 0/r32/eax + # if target-type is an atom, it must be a literal or int +$check-mu-read-from-stream-stmt:check-target-is-compound: + 81 7/subop/compare *edx 0/imm32/false # Type-tree-is-atom + 0f 85/jump-if-!= $check-mu-read-from-stream-stmt:error-target-type-not-address/disp32 +$check-mu-read-from-stream-stmt:check-target-type: + # target type must start with (addr ...) + (lookup *(edx+4) *(edx+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 2) # addr => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-read-from-stream-stmt:error-target-type-not-address/disp32 + # if tail(base-type) != tail(target-type) abort + (type-tail %ebx) # => eax + 89/<- %ebx 0/r32/eax + (type-tail %edx) # => eax + (type-equal? %ebx %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-read-from-stream-stmt:error-invalid-target-type/disp32 +$check-mu-read-from-stream-stmt:check-too-many-inouts: + # - check for too many inouts + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $check-mu-read-from-stream-stmt:error-too-many-inouts/disp32 +$check-mu-read-from-stream-stmt:check-unexpected-output: + # - check for any output + (lookup *(esi+0x14) *(esi+0x18)) # Stmt1-outputs Stmt1-outputs => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $check-mu-read-from-stream-stmt:error-unexpected-output/disp32 +$check-mu-read-from-stream-stmt:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$check-mu-read-from-stream-stmt:error-invalid-base-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt read-from-stream: var '") + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' must be an addr to a stream\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-read-from-stream-stmt:error-too-few-inouts: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt read-from-stream: too few inouts (2 required)\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-read-from-stream-stmt:error-target-type-not-address: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt read-from-stream: target '") + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' must be an addr\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-read-from-stream-stmt:error-invalid-target-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt read-from-stream: second inout '") + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' does not have the right type\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-read-from-stream-stmt:error-too-many-inouts: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt read-from-stream: too many inouts (2 required)\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-read-from-stream-stmt:error-unexpected-output: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt read-from-stream: unexpected output\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +check-mu-write-to-stream-stmt: # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + 57/push-edi + # esi = stmt + 8b/-> *(ebp+8) 6/r32/esi + # - check for 0 inouts + # var base/ecx: (addr var) = stmt->inouts->value + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax +$check-mu-write-to-stream-stmt:check-no-inouts: + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-write-to-stream-stmt:error-too-few-inouts/disp32 + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %ecx 0/r32/eax + # - check base type is (addr stream T) + # var base-type/ebx: (addr type-tree) = lookup(base->type) + (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + 89/<- %ebx 0/r32/eax +$check-mu-write-to-stream-stmt:check-base-is-compound: + # if base-type is an atom, abort + 81 7/subop/compare *ebx 0/imm32/false # Type-tree-is-atom + 0f 85/jump-if-!= $check-mu-write-to-stream-stmt:error-invalid-base-type/disp32 +$check-mu-write-to-stream-stmt:check-base-is-addr: + # if type->left not addr, abort + (lookup *(ebx+4) *(ebx+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 2) # addr => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-write-to-stream-stmt:error-invalid-base-type/disp32 +$check-mu-write-to-stream-stmt:check-base-is-addr-to-stream: + # base-type = base-type->right + (lookup *(ebx+0xc) *(ebx+0x10)) # Type-tree-right Type-tree-right => eax + 89/<- %ebx 0/r32/eax + # ensure base-type->left == stream + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 0xb) # stream => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-write-to-stream-stmt:error-invalid-base-type/disp32 + # - check target type is (addr T) + # var target/ecx: (addr stmt-var) = stmt->inouts->next->value + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax +$check-mu-write-to-stream-stmt:check-single-inout: + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-write-to-stream-stmt:error-too-few-inouts/disp32 + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %ecx 0/r32/eax + # var target-type/edx: (addr type-tree) + (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + 89/<- %edx 0/r32/eax + # if target-type is an atom, it must be a literal or int +$check-mu-write-to-stream-stmt:check-target-is-compound: + 81 7/subop/compare *edx 0/imm32/false # Type-tree-is-atom + 0f 85/jump-if-!= $check-mu-write-to-stream-stmt:error-target-type-not-address/disp32 +$check-mu-write-to-stream-stmt:check-target-type: + # target type must start with (addr ...) + (lookup *(edx+4) *(edx+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 2) # addr => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-write-to-stream-stmt:error-target-type-not-address/disp32 + # if tail(base-type) != tail(target-type) abort + (type-tail %ebx) # => eax + 89/<- %ebx 0/r32/eax + (type-tail %edx) # => eax + (type-equal? %ebx %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $check-mu-write-to-stream-stmt:error-invalid-target-type/disp32 +$check-mu-write-to-stream-stmt:check-too-many-inouts: + # - check for too many inouts + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $check-mu-write-to-stream-stmt:error-too-many-inouts/disp32 +$check-mu-write-to-stream-stmt:check-unexpected-output: + # - check for any output + (lookup *(esi+0x14) *(esi+0x18)) # Stmt1-outputs Stmt1-outputs => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $check-mu-write-to-stream-stmt:error-unexpected-output/disp32 +$check-mu-write-to-stream-stmt:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$check-mu-write-to-stream-stmt:error-invalid-base-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt write-to-stream: var '") + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' must be an addr to a stream\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-write-to-stream-stmt:error-too-few-inouts: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt write-to-stream: too few inouts (2 required)\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-write-to-stream-stmt:error-target-type-not-address: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt write-to-stream: target '") + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' must be an addr\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-write-to-stream-stmt:error-invalid-target-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt write-to-stream: second inout '") + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' does not have the right type\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-write-to-stream-stmt:error-too-many-inouts: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt write-to-stream: too many inouts (2 required)\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-write-to-stream-stmt:error-unexpected-output: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt write-to-stream: unexpected output\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +check-mu-convert-stmt: # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 56/push-esi + 57/push-edi +$check-mu-convert-stmt:get-output: + # esi = stmt + 8b/-> *(ebp+8) 6/r32/esi + # var output/edi: (addr stmt-var) = stmt->outputs + (lookup *(esi+0x14) *(esi+0x18)) # Stmt1-outputs Stmt1-outputs => eax + 89/<- %edi 0/r32/eax + # zero outputs + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-convert-stmt:error-no-output/disp32 + # > 1 output + (lookup *(edi+8) *(edi+0xc)) # Stmt-var-next Stmt-var-next => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-mu-convert-stmt:error-too-many-outputs/disp32 +$check-mu-convert-stmt:get-inout: + # var inout/esi: (addr stmt-var) = stmt->inouts + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 89/<- %esi 0/r32/eax + # zero inouts + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-convert-stmt:error-no-inout/disp32 + # > 1 inout + (lookup *(esi+8) *(esi+0xc)) # Stmt-var-next Stmt-var-next => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= $check-mu-convert-stmt:error-too-many-inouts/disp32 +$check-mu-convert-stmt:types: + # var inout-type/ecx: (addr type-tree) = inout->value->type + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + 89/<- %ecx 0/r32/eax + # if (inout->is-deref?) inout-type = inout-type->payload + 8b/-> *(esi+0x10) 0/r32/eax # Stmt-var-is-deref + 3d/compare-eax-and 0/imm32/false + { + 74/jump-if-= break/disp8 + (lookup *(ecx+0xc) *(ecx+0x10)) # Type-tree-right Type-tree-right => eax + # if inout-type->right is null, t = inout-type->left + 81 7/subop/compare *(eax+0xc) 0/imm32 # Type-tree-right + { + 75/jump-if-!= break/disp8 + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } + 89/<- %ecx 0/r32/eax + } + # if input is not int or float, abort + { + (is-simple-mu-type? %ecx 1) # int => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 + (is-simple-mu-type? %ecx 0xf) # float => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 + e9/jump $check-mu-convert-stmt:error-invalid-inout-type/disp32 + } + # if output not in register, abort + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $check-mu-convert-stmt:error-output-not-in-register/disp32 + # var output-type/edx: (addr type-tree) = output->value->type + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + 89/<- %edx 0/r32/eax + # if output is not int or float, abort + { + (is-simple-mu-type? %edx 1) # int => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 + (is-simple-mu-type? %edx 0xf) # float => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 + e9/jump $check-mu-convert-stmt:error-invalid-output-type/disp32 + } + # if both are ints, abort + { + (is-simple-mu-type? %edx 1) # int => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (is-simple-mu-type? %ecx 1) # int => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + e9/jump $check-mu-convert-stmt:error-int-to-int/disp32 + } + # if both are floats, abort + { + (is-simple-mu-type? %edx 0xf) # float => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (is-simple-mu-type? %ecx 0xf) # float => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + e9/jump $check-mu-convert-stmt:error-float-to-float/disp32 + } +$check-mu-convert-stmt:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$check-mu-convert-stmt:error-no-inout: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'convert' expects an inout\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-convert-stmt:error-too-many-inouts: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'convert' must have just one inout\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-convert-stmt:error-no-output: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'convert' expects an output\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-convert-stmt:error-output-not-in-register: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt convert: output '") + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' not in a register\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-convert-stmt:error-too-many-outputs: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt 'convert' must have just one output\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-convert-stmt:error-invalid-inout-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt convert: inout '") + (lookup *esi *(esi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' must be an int or float\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-convert-stmt:error-invalid-output-type: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt convert: output '") + (lookup *edi *(edi+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) "' must be an int or float\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-convert-stmt:error-int-to-int: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt convert: no need to convert int to int\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +$check-mu-convert-stmt:error-float-to-float: + (write-buffered *(ebp+0x10) "fn ") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) ": stmt convert: no need to convert float to float\n") + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +check-mu-call: # stmt: (addr stmt), callee: (addr function), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # var type-parameters: (addr table (handle array byte) (addr type-tree) 8) + 68/push 0/imm32 + # var type-parameters-storage: (table (handle array byte) (addr type-tree) 8) + 81 5/subop/subtract %esp 0x60/imm32 + 68/push 0x60/imm32/size + 68/push 0/imm32/read + 68/push 0/imm32/write + # save a pointer to type-parameters-storage at type-parameters + 89/<- *(ebp-4) 4/r32/esp + (clear-stream *(ebp-4)) + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + 57/push-edi + # esi = stmt + 8b/-> *(ebp+8) 6/r32/esi + # edi = callee + 8b/-> *(ebp+0xc) 7/r32/edi + # var inouts/ecx: (addr stmt-var) = lookup(stmt->inouts) + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 89/<- %ecx 0/r32/eax + # var expected/edx: (addr list var) = lookup(f->inouts) + (lookup *(edi+8) *(edi+0xc)) # Function-inouts Function-inouts => eax + 89/<- %edx 0/r32/eax + { +$check-mu-call:check-for-inouts: + # if (inouts == 0) break + 81 7/subop/compare %ecx 0/imm32 + 0f 84/jump-if-= break/disp32 + # if (expected == 0) error + 81 7/subop/compare %edx 0/imm32 + 0f 84/jump-if-= break/disp32 +$check-mu-call:check-null-addr: + # if (inouts->value->name == "0") continue + (lookup *ecx *(ecx+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (string-equal? %eax "0") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $check-mu-call:continue-to-next-inout/disp32 +$check-mu-call:check-inout-type: + # var t/ebx: (addr type-tree) = inouts->value->type + (lookup *ecx *(ecx+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + 89/<- %ebx 0/r32/eax + # if (inouts->is-deref?) t = t->right + 81 7/subop/compare *(ecx+0x10) 0/imm32/false # Stmt-var-is-deref + { + 74/jump-if-= break/disp8 + (lookup *(ebx+0xc) *(ebx+0x10)) # Type-tree-right Type-tree-right => eax + 89/<- %ebx 0/r32/eax + # if t->right is null, t = t->left + 81 7/subop/compare *(ebx+0xc) 0/imm32 # Type-tree-right + 75/jump-if-!= break/disp8 + (lookup *(ebx+4) *(ebx+8)) # Type-tree-left Type-tree-left => eax + 89/<- %ebx 0/r32/eax + } + # var v2/eax: (addr v) = lookup(expected->value) + (lookup *edx *(edx+4)) # List-value List-value => eax + # var t2/eax: (addr type-tree) = lookup(v2->type) + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + # if (t != t2) error + (type-match? %eax %ebx *(ebp-4)) # => eax + 3d/compare-eax-and 0/imm32/false + { + 0f 85/jump-if-!= break/disp32 + (write-buffered *(ebp+0x14) "fn ") + 8b/-> *(ebp+0x10) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x14) %eax) + (write-buffered *(ebp+0x14) ": call ") + (lookup *edi *(edi+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x14) %eax) + (write-buffered *(ebp+0x14) ": type for inout '") + (lookup *ecx *(ecx+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x14) %eax) + (write-buffered *(ebp+0x14) "' is not right\n") + (flush *(ebp+0x14)) + (stop *(ebp+0x18) 1) + } +$check-mu-call:continue-to-next-inout: + # inouts = lookup(inouts->next) + (lookup *(ecx+8) *(ecx+0xc)) # Stmt-var-next Stmt-var-next => eax + 89/<- %ecx 0/r32/eax + # expected = lookup(expected->next) + (lookup *(edx+8) *(edx+0xc)) # List-next List-next => eax + 89/<- %edx 0/r32/eax + # + e9/jump loop/disp32 + } +$check-mu-call:check-inout-count: + # if (inouts == expected) proceed + 39/compare %ecx 2/r32/edx + { + 0f 84/jump-if-= break/disp32 + # exactly one of the two is null + # if (inouts == 0) error("too many inouts") + { + 81 7/subop/compare %ecx 0/imm32 + 0f 84/jump-if-= break/disp32 + (write-buffered *(ebp+0x14) "fn ") + 8b/-> *(ebp+0x10) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x14) %eax) + (write-buffered *(ebp+0x14) ": call ") + (lookup *edi *(edi+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x14) %eax) + (write-buffered *(ebp+0x14) ": too many inouts\n") + (flush *(ebp+0x14)) + (stop *(ebp+0x18) 1) + } + # if (expected == 0) error("too few inouts") + { + 81 7/subop/compare %edx 0/imm32 + 0f 84/jump-if-= break/disp32 + (write-buffered *(ebp+0x14) "fn ") + 8b/-> *(ebp+0x10) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x14) %eax) + (write-buffered *(ebp+0x14) ": call ") + (lookup *edi *(edi+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x14) %eax) + (write-buffered *(ebp+0x14) ": too few inouts\n") + (flush *(ebp+0x14)) + (stop *(ebp+0x18) 1) + } + } +$check-mu-call:check-outputs: + # var outputs/ecx: (addr stmt-var) = lookup(stmt->outputs) + (lookup *(esi+0x14) *(esi+0x18)) # Stmt1-outputs Stmt1-outputs => eax + 89/<- %ecx 0/r32/eax + # var expected/edx: (addr list var) = lookup(f->outputs) + (lookup *(edi+0x10) *(edi+0x14)) # Function-outputs Function-outputs => eax + 89/<- %edx 0/r32/eax + { +$check-mu-call:check-for-outputs: + # if (outputs == 0) break + 81 7/subop/compare %ecx 0/imm32 + 0f 84/jump-if-= break/disp32 + # if (expected == 0) error + 81 7/subop/compare %edx 0/imm32 + 0f 84/jump-if-= break/disp32 +$check-mu-call:check-output-type: + # var v/eax: (addr v) = lookup(outputs->value) + (lookup *ecx *(ecx+4)) # Stmt-var-value Stmt-var-value => eax + # var t/ebx: (addr type-tree) = lookup(v->type) + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + 89/<- %ebx 0/r32/eax + # if (outputs->is-deref?) t = t->right # TODO: check that t->left is an addr + 81 7/subop/compare *(ecx+0x10) 0/imm32/false # Stmt-var-is-deref + { + 74/jump-if-= break/disp8 + (lookup *(ebx+0xc) *(ebx+0x10)) # Type-tree-right Type-tree-right => eax + 89/<- %ebx 0/r32/eax + } + # var v2/eax: (addr v) = lookup(expected->value) + (lookup *edx *(edx+4)) # List-value List-value => eax + # var t2/eax: (addr type-tree) = lookup(v2->type) + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + # if (t != t2) error + (type-match? %eax %ebx *(ebp-4)) # => eax + 3d/compare-eax-and 0/imm32/false + { + 0f 85/jump-if-!= break/disp32 + (write-buffered *(ebp+0x14) "fn ") + 8b/-> *(ebp+0x10) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x14) %eax) + (write-buffered *(ebp+0x14) ": call ") + (lookup *edi *(edi+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x14) %eax) + (write-buffered *(ebp+0x14) ": type for output '") + (lookup *ecx *(ecx+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x14) %eax) + (write-buffered *(ebp+0x14) "' is not right\n") + (flush *(ebp+0x14)) + (stop *(ebp+0x18) 1) + } +$check-mu-call:check-output-register: + # var v/eax: (addr v) = lookup(outputs->value) + (lookup *ecx *(ecx+4)) # Stmt-var-value Stmt-var-value => eax + # var r/ebx: (addr array byte) = lookup(v->register) + (lookup *(eax+18) *(eax+0x1c)) # Var-register Var-register => eax + 89/<- %ebx 0/r32/eax + # if (r == 0) error + 3d/compare-eax-and 0/imm32 + { + 0f 85/jump-if-!= break/disp32 + (write-buffered *(ebp+0x14) "fn ") + 8b/-> *(ebp+0x10) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x14) %eax) + (write-buffered *(ebp+0x14) ": call ") + (lookup *edi *(edi+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x14) %eax) + (write-buffered *(ebp+0x14) ": output '") + (lookup *ecx *(ecx+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x14) %eax) + (write-buffered *(ebp+0x14) "' is not in a register\n") + (flush *(ebp+0x14)) + (stop *(ebp+0x18) 1) + } + # var v2/eax: (addr v) = lookup(expected->value) + (lookup *edx *(edx+4)) # Stmt-var-value Stmt-var-value => eax + # var r2/eax: (addr array byte) = lookup(v2->register) + (lookup *(eax+18) *(eax+0x1c)) # Var-register Var-register => eax + # if (r != r2) error + (string-equal? %eax %ebx) # => eax + 3d/compare-eax-and 0/imm32/false + { + 0f 85/jump-if-!= break/disp32 + (write-buffered *(ebp+0x14) "fn ") + 8b/-> *(ebp+0x10) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x14) %eax) + (write-buffered *(ebp+0x14) ": call ") + (lookup *edi *(edi+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x14) %eax) + (write-buffered *(ebp+0x14) ": register for output '") + (lookup *ecx *(ecx+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x14) %eax) + (write-buffered *(ebp+0x14) "' is not right\n") + (flush *(ebp+0x14)) + (stop *(ebp+0x18) 1) + } +$check-mu-call:continue-to-next-output: + # outputs = lookup(outputs->next) + (lookup *(ecx+8) *(ecx+0xc)) # Stmt-var-next Stmt-var-next => eax + 89/<- %ecx 0/r32/eax + # expected = lookup(expected->next) + (lookup *(edx+8) *(edx+0xc)) # List-next List-next => eax + 89/<- %edx 0/r32/eax + # + e9/jump loop/disp32 + } +$check-mu-call:check-output-count: + # if (outputs == expected) proceed + 39/compare %ecx 2/r32/edx + { + 0f 84/jump-if-= break/disp32 + # exactly one of the two is null + # if (outputs == 0) error("too many outputs") + { + 81 7/subop/compare %ecx 0/imm32 + 0f 84/jump-if-= break/disp32 + (write-buffered *(ebp+0x14) "fn ") + 8b/-> *(ebp+0x10) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x14) %eax) + (write-buffered *(ebp+0x14) ": call ") + (lookup *edi *(edi+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x14) %eax) + (write-buffered *(ebp+0x14) ": too many outputs\n") + (flush *(ebp+0x14)) + (stop *(ebp+0x18) 1) + } + # if (expected == 0) error("too few outputs") + { + 81 7/subop/compare %edx 0/imm32 + 0f 84/jump-if-= break/disp32 + (write-buffered *(ebp+0x14) "fn ") + 8b/-> *(ebp+0x10) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x14) %eax) + (write-buffered *(ebp+0x14) ": call ") + (lookup *edi *(edi+4)) # Function-name Function-name => eax + (write-buffered *(ebp+0x14) %eax) + (write-buffered *(ebp+0x14) ": too few outputs\n") + (flush *(ebp+0x14)) + (stop *(ebp+0x18) 1) + } + } +$check-mu-call:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . reclaim locals exclusively on the stack + 81 0/subop/add %esp 0x70/imm32 + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# like type-equal? but takes literals type parameters into account +type-match?: # def: (addr type-tree), call: (addr type-tree), type-parameters: (addr table (handle array byte) (addr type-tree)) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # if (call is literal and def is numberlike) return true + { +$type-match?:check-literal-int: + (is-simple-mu-type? *(ebp+0xc) 0) # literal => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (is-mu-numberlike-output? *(ebp+8)) # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + b8/copy-to-eax 1/imm32/true + e9/jump $type-match?:end/disp32 + } + # if (call is literal-string and def is string) return true + { +$type-match?:check-literal-string: + (is-simple-mu-type? *(ebp+0xc) 0x10) # literal-string => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (is-mu-string-type? *(ebp+8)) # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + b8/copy-to-eax 1/imm32/true + e9/jump $type-match?:end/disp32 + } +$type-match?:baseline: + # otherwise fall back + (type-component-match? *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax +$type-match?:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +type-component-match?: # def: (addr type-tree), call: (addr type-tree), type-parameters: (addr table (handle array byte) (addr type-tree)) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + 52/push-edx + 53/push-ebx + # ecx = def + 8b/-> *(ebp+8) 1/r32/ecx + # edx = call + 8b/-> *(ebp+0xc) 2/r32/edx +$type-component-match?:compare-addr: + # if (def == call) return true + 8b/-> %ecx 0/r32/eax # Var-type + 39/compare %edx 0/r32/eax # Var-type + b8/copy-to-eax 1/imm32/true + 0f 84/jump-if-= $type-component-match?:end/disp32 + # if (def == 0) return false + b8/copy-to-eax 0/imm32/false + 81 7/subop/compare %ecx 0/imm32 # Type-tree-is-atom + 0f 84/jump-if-= $type-component-match?:end/disp32 + # if (call == 0) return false + 81 7/subop/compare %edx 0/imm32 # Type-tree-is-atom + 0f 84/jump-if-= $type-component-match?:end/disp32 + # if def is a type parameter, just check in type-parameters + { +$type-component-match?:check-type-parameter: + 81 7/subop/compare *ecx 0/imm32/false # Type-tree-is-atom + 74/jump-if-= break/disp8 + 81 7/subop/compare *(ecx+4) 0xa/imm32/type-parameter # Type-tree-value + 75/jump-if-!= break/disp8 +$type-component-match?:type-parameter: + (type-parameter-match? *(ecx+8) *(ecx+0xc) %edx *(ebp+0x10)) # => eax + e9/jump $type-component-match?:end/disp32 + } + # if def is a list containing just a type parameter, just check in type-parameters + { +$type-component-match?:check-list-type-parameter: + # if def is a list.. + 81 7/subop/compare *ecx 0/imm32/false # Type-tree-is-atom + 75/jump-if-!= break/disp8 + # ..that's a singleton + 81 7/subop/compare *(ecx+0xc) 0/imm32 # Type-tree-left + 75/jump-if-!= break/disp8 + # ..and whose head is a type parameter + (lookup *(ecx+4) *(ecx+8)) # Type-tree-left Type-tree-left => eax + 81 7/subop/compare *eax 0/imm32/false # Type-tree-is-atom + 74/jump-if-= break/disp8 + 81 7/subop/compare *(eax+4) 0xa/imm32/type-parameter # Type-tree-value + 75/jump-if-!= break/disp8 +$type-component-match?:list-type-parameter: + (type-parameter-match? *(eax+8) *(eax+0xc) %edx *(ebp+0x10)) # => eax + e9/jump $type-component-match?:end/disp32 + } +$type-component-match?:compare-atom-state: + # if (def->is-atom? != call->is-atom?) return false + 8b/-> *ecx 3/r32/ebx # Type-tree-is-atom + 39/compare *edx 3/r32/ebx # Type-tree-is-atom + b8/copy-to-eax 0/imm32/false + 0f 85/jump-if-!= $type-component-match?:end/disp32 + # if def->is-atom? return (def->value == call->value) + { +$type-component-match?:check-atom: + 81 7/subop/compare %ebx 0/imm32/false + 74/jump-if-= break/disp8 +$type-component-match?:is-atom: + 8b/-> *(ecx+4) 0/r32/eax # Type-tree-value + 39/compare *(edx+4) 0/r32/eax # Type-tree-value + 0f 94/set-if-= %al + 81 4/subop/and %eax 0xff/imm32 + e9/jump $type-component-match?:end/disp32 + } +$type-component-match?:check-left: + # if (!type-component-match?(def->left, call->left)) return false + (lookup *(ecx+4) *(ecx+8)) # Type-tree-left Type-tree-left => eax + 89/<- %ebx 0/r32/eax + (lookup *(edx+4) *(edx+8)) # Type-tree-left Type-tree-left => eax + (type-component-match? %ebx %eax *(ebp+0x10)) # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= $type-component-match?:end/disp8 +$type-component-match?:check-right: + # return type-component-match?(def->right, call->right) + (lookup *(ecx+0xc) *(ecx+0x10)) # Type-tree-right Type-tree-right => eax + 89/<- %ebx 0/r32/eax + (lookup *(edx+0xc) *(edx+0x10)) # Type-tree-right Type-tree-right => eax + (type-component-match? %ebx %eax *(ebp+0x10)) # => eax +$type-component-match?:end: + # . restore registers + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +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 + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # + (get-or-insert-handle *(ebp+0x14) *(ebp+8) *(ebp+0xc) 0xc) # => eax + # if parameter wasn't saved, save it + { + 81 7/subop/compare *eax 0/imm32 + 75/jump-if-!= break/disp8 + 8b/-> *(ebp+0x10) 1/r32/ecx + 89/<- *eax 1/r32/ecx + } + # + (type-equal? *(ebp+0x10) *eax) # => eax +$type-parameter-match?:end: + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +size-of: # v: (addr var) -> result/eax: int + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # var t/ecx: (addr type-tree) = lookup(v->type) + 8b/-> *(ebp+8) 1/r32/ecx +#? (write-buffered Stderr "size-of ") +#? (write-int32-hex-buffered Stderr %ecx) +#? (write-buffered Stderr Newline) +#? (write-buffered Stderr "type allocid: ") +#? (write-int32-hex-buffered Stderr *(ecx+8)) +#? (write-buffered Stderr Newline) +#? (flush Stderr) + (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + 89/<- %ecx 0/r32/eax + # if is-mu-array?(t) return size-of-array(t) + { + (is-mu-array? %ecx) # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (size-of-array %ecx) # => eax + eb/jump $size-of:end/disp8 + } + # if is-mu-stream?(t) return size-of-stream(t) + { + (is-mu-stream? %ecx) # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (size-of-stream %ecx) # => eax + eb/jump $size-of:end/disp8 + } + # if (!t->is-atom?) t = lookup(t->left) + { + 81 7/subop/compare *ecx 0/imm32/false # Type-tree-is-atom + 75/jump-if-!= break/disp8 + (lookup *(ecx+4) *(ecx+8)) # Type-tree-left Type-tree-left => eax + 89/<- %ecx 0/r32/eax + } + # TODO: assert t->is-atom? + (size-of-type-id *(ecx+4)) # Type-tree-value => eax +$size-of:end: + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +size-of-deref: # v: (addr var) -> result/eax: int + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # var t/ecx: (addr type-tree) = lookup(v->type) + 8b/-> *(ebp+8) 1/r32/ecx + (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + 89/<- %ecx 0/r32/eax + # TODO: assert(t is an addr) + # t = lookup(t->right) + (lookup *(ecx+0xc) *(ecx+0x10)) # Type-tree-right Type-tree-right => eax + 89/<- %ecx 0/r32/eax + # if is-mu-array?(t) return size-of-array(t) + { + (is-mu-array? %ecx) # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (size-of-array %ecx) # => eax + eb/jump $size-of-deref:end/disp8 + } + # if is-mu-stream?(t) return size-of-stream(t) + { + (is-mu-stream? %ecx) # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (size-of-stream %ecx) # => eax + eb/jump $size-of-deref:end/disp8 + } + # if (!t->is-atom?) t = lookup(t->left) + { + 81 7/subop/compare *ecx 0/imm32/false # Type-tree-is-atom + 75/jump-if-!= break/disp8 + (lookup *(ecx+4) *(ecx+8)) # Type-tree-left Type-tree-left => eax + 89/<- %ecx 0/r32/eax + } + # TODO: assert t->is-atom? + (size-of-type-id *(ecx+4)) # Type-tree-value => eax +$size-of-deref:end: + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +is-mu-array?: # t: (addr type-tree) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # ecx = t + 8b/-> *(ebp+8) 1/r32/ecx + # if t->is-atom?, return false + 81 7/subop/compare *ecx 0/imm32/false # Type-tree-is-atom + 75/jump-if-!= $is-mu-array?:return-false/disp8 + # if !t->left->is-atom?, return false + (lookup *(ecx+4) *(ecx+8)) # Type-tree-left Type-tree-left => eax + 81 7/subop/compare *eax 0/imm32/false # Type-tree-is-atom + 74/jump-if-= $is-mu-array?:return-false/disp8 + # return t->left->value == array + 81 7/subop/compare *(eax+4) 3/imm32/array-type-id # Type-tree-value + 0f 94/set-if-= %al + 81 4/subop/and %eax 0xff/imm32 + eb/jump $is-mu-array?:end/disp8 +$is-mu-array?:return-false: + b8/copy-to-eax 0/imm32/false +$is-mu-array?:end: + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# size of a statically allocated array where the size is part of the type expression +size-of-array: # a: (addr type-tree) -> result/eax: int + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + 52/push-edx + # + 8b/-> *(ebp+8) 1/r32/ecx + # TODO: assert that a->left is 'array' + (lookup *(ecx+0xc) *(ecx+0x10)) # Type-tree-right Type-tree-right => eax + 89/<- %ecx 0/r32/eax + # var elem-type/edx: type-id = a->right->left->value + (lookup *(ecx+4) *(ecx+8)) # Type-tree-left Type-tree-left => eax + 8b/-> *(eax+4) 2/r32/edx # Type-tree-value + # TODO: assert that a->right->right->left->value == size + # var array-size/ecx: int = a->right->right->left->value-size + (lookup *(ecx+0xc) *(ecx+0x10)) # Type-tree-right Type-tree-right => eax + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + 8b/-> *(eax+8) 1/r32/ecx # Type-tree-value-size + # return 4 + array-size * size-of(elem-type) + (size-of-type-id-as-array-element %edx) # => eax + f7 4/subop/multiply-into-edx-eax %ecx + 05/add-to-eax 4/imm32 # for array size + # TODO: check edx for overflow +$size-of-array:end: + # . restore registers + 5a/pop-to-edx + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +is-mu-stream?: # t: (addr type-tree) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # ecx = t + 8b/-> *(ebp+8) 1/r32/ecx + # if t->is-atom?, return false + 81 7/subop/compare *ecx 0/imm32/false # Type-tree-is-atom + 75/jump-if-!= $is-mu-stream?:return-false/disp8 + # if !t->left->is-atom?, return false + (lookup *(ecx+4) *(ecx+8)) # Type-tree-left Type-tree-left => eax + 81 7/subop/compare *eax 0/imm32/false # Type-tree-is-atom + 74/jump-if-= $is-mu-stream?:return-false/disp8 + # return t->left->value == stream + 81 7/subop/compare *(eax+4) 0xb/imm32/stream-type-id # Type-tree-value + 0f 94/set-if-= %al + 81 4/subop/and %eax 0xff/imm32 + eb/jump $is-mu-stream?:end/disp8 +$is-mu-stream?:return-false: + b8/copy-to-eax 0/imm32/false +$is-mu-stream?:end: + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# size of a statically allocated stream where the size is part of the type expression +size-of-stream: # a: (addr type-tree) -> result/eax: int + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # + (size-of-array *(ebp+8)) # assumes we ignore the actual type name 'array' in the type + 05/add-to-eax 8/imm32 # for read/write pointers +$size-of-stream:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +size-of-type-id: # t: type-id -> result/eax: int + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # var out/ecx: (handle typeinfo) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %ecx 4/r32/esp + # eax = t + 8b/-> *(ebp+8) 0/r32/eax + # if t is a literal, return 0 + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= $size-of-type-id:end/disp32 # eax changes type from type-id to int + # if t is a byte, return 4 (because we don't really support non-multiples of 4) + 3d/compare-eax-and 8/imm32/byte + { + 75/jump-if-!= break/disp8 + b8/copy-to-eax 4/imm32 + eb/jump $size-of-type-id:end/disp8 + } + # if t is a handle, return 8 + 3d/compare-eax-and 4/imm32/handle + { + 75/jump-if-!= break/disp8 + b8/copy-to-eax 8/imm32 + eb/jump $size-of-type-id:end/disp8 # eax changes type from type-id to int + } + # if t is a slice, return 8 + 3d/compare-eax-and 0xc/imm32/slice + { + 75/jump-if-!= break/disp8 + b8/copy-to-eax 8/imm32 + eb/jump $size-of-type-id:end/disp8 # eax changes type from type-id to int + } + # if t is a user-defined type, return its size + # TODO: support non-atom type + (find-typeinfo %eax %ecx) + { + 81 7/subop/compare *ecx 0/imm32 + 74/jump-if-= break/disp8 +$size-of-type-id:user-defined: + (lookup *ecx *(ecx+4)) # => eax + 8b/-> *(eax+0xc) 0/r32/eax # Typeinfo-total-size-in-bytes + eb/jump $size-of-type-id:end/disp8 + } + # otherwise return the word size + b8/copy-to-eax 4/imm32 +$size-of-type-id:end: + # . reclaim locals + 81 0/subop/add %esp 8/imm32 + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# Minor violation of our type system since it returns an addr. But we could +# replace it with a handle some time. +# Returns null if t is an atom. +type-tail: # t: (addr type-tree) -> out/eax: (addr type-tree) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # eax = 0 + b8/copy-to-eax 0/imm32 + # ecx = t + 8b/-> *(ebp+8) 1/r32/ecx +$type-tail:check-atom: + # if t->is-atom? return 0 + 81 7/subop/compare *ecx 0/imm32/false # Type-tree-is-atom + 0f 85/jump-if-!= $type-tail:end/disp32 + # var tail = t->right + (lookup *(ecx+0xc) *(ecx+0x10)) # Type-tree-right Type-tree-right => eax + 89/<- %ecx 0/r32/eax +$type-tail:check-singleton: + # if (tail->right == 0) return tail->left + { + 81 7/subop/compare *(ecx+0xc) 0/imm32 # Type-tree-right + 75/jump-if-!= break/disp8 + (lookup *(ecx+4) *(ecx+8)) # Type-tree-left Type-tree-left => eax + e9/jump $type-tail:end/disp32 + } + # if tail->right->left is an array-capacity, return tail->left + { +$type-tail:check-array-capacity: + (lookup *(ecx+0xc) *(ecx+0x10)) # Type-tree-right Type-tree-right => eax + 81 7/subop/compare *eax 0/imm32/false # Type-tree-is-atom + 75/jump-if-!= break/disp8 +$type-tail:check-array-capacity-1: + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + 3d/compare-eax-and 0/imm32 + 74/jump-if-= break/disp8 +$type-tail:check-array-capacity-2: + (is-simple-mu-type? %eax 9) # array-capacity => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 +$type-tail:array-capacity: + (lookup *(ecx+4) *(ecx+8)) # Type-tree-left Type-tree-left => eax + eb/jump $type-tail:end/disp8 + } +$type-tail:check-compound-left: + # if !tail->left->is-atom? return tail->left + (lookup *(ecx+4) *(ecx+8)) # Type-tree-left Type-tree-left => eax + 81 7/subop/compare *eax 0/imm32/false # Type-tree-is-atom + 74/jump-if-= $type-tail:end/disp8 +$type-tail:return-tail: + # return tail + 89/<- %eax 1/r32/ecx +$type-tail:end: + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +type-equal?: # a: (addr type-tree), b: (addr type-tree) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + 52/push-edx + 53/push-ebx + # ecx = a + 8b/-> *(ebp+8) 1/r32/ecx + # edx = b + 8b/-> *(ebp+0xc) 2/r32/edx +$type-equal?:compare-addr: + # if (a == b) return true + 8b/-> %ecx 0/r32/eax # Var-type + 39/compare %edx 0/r32/eax # Var-type + b8/copy-to-eax 1/imm32/true + 0f 84/jump-if-= $type-equal?:end/disp32 +$type-equal?:compare-null-a: + # if (a == 0) return false + b8/copy-to-eax 0/imm32/false + 81 7/subop/compare %ecx 0/imm32 + 0f 84/jump-if-= $type-equal?:end/disp32 +$type-equal?:compare-null-b: + # if (b == 0) return false + 81 7/subop/compare %edx 0/imm32 + 0f 84/jump-if-= $type-equal?:end/disp32 +$type-equal?:compare-atom-state: + # if (a->is-atom? != b->is-atom?) return false + 8b/-> *ecx 3/r32/ebx # Type-tree-is-atom + 39/compare *edx 3/r32/ebx # Type-tree-is-atom + b8/copy-to-eax 0/imm32/false + 0f 85/jump-if-!= $type-equal?:end/disp32 + # if a->is-atom? return (a->value == b->value) + { +$type-equal?:check-atom: + 81 7/subop/compare %ebx 0/imm32/false + 74/jump-if-= break/disp8 +$type-equal?:is-atom: + 8b/-> *(ecx+4) 0/r32/eax # Type-tree-value + 39/compare *(edx+4) 0/r32/eax # Type-tree-value + 0f 94/set-if-= %al + 81 4/subop/and %eax 0xff/imm32 + e9/jump $type-equal?:end/disp32 + } +$type-equal?:check-left: + # if (!type-equal?(a->left, b->left)) return false + (lookup *(ecx+4) *(ecx+8)) # Type-tree-left Type-tree-left => eax + 89/<- %ebx 0/r32/eax + (lookup *(edx+4) *(edx+8)) # Type-tree-left Type-tree-left => eax + (type-equal? %eax %ebx) # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= $type-equal?:end/disp8 +$type-equal?:check-right: + # return type-equal?(a->right, b->right) + (lookup *(ecx+0xc) *(ecx+0x10)) # Type-tree-right Type-tree-right => eax + 89/<- %ebx 0/r32/eax + (lookup *(edx+0xc) *(edx+0x10)) # Type-tree-right Type-tree-right => eax + (type-equal? %eax %ebx) # => eax +$type-equal?:end: + # . restore registers + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +####################################################### +# Code-generation +####################################################### + +== data + +# Global state added to each var record when performing code-generation. +Curr-local-stack-offset: # (addr int) + 0/imm32 + +== code + +# We may not need to pass err/ed everywhere here. I think they're relics of Mu +# getting type checks later in life. +# But we do need them for runtime checks, particularly array index bounds checks. +# So perhaps it's not worth taking them out. They're a safety net. + +emit-subx: # out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + # var curr/eax: (addr function) = *Program->functions + (lookup *_Program-functions *_Program-functions->payload) # => eax + { + # if (curr == null) break + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= break/disp32 + (emit-subx-function *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10)) + # curr = lookup(curr->next) + (lookup *(eax+0x20) *(eax+0x24)) # Function-next Function-next => eax + e9/jump loop/disp32 + } +$emit-subx:end: + # . restore registers + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +emit-subx-function: # out: (addr buffered-file), f: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # some preprocessing + (populate-mu-type-offsets-in-inouts *(ebp+0xc)) + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + # initialize some global state + c7 0/subop/copy *Curr-block-depth 1/imm32 # Important: keep this in sync with the parse phase + c7 0/subop/copy *Curr-local-stack-offset 0/imm32 + # ecx = f + 8b/-> *(ebp+0xc) 1/r32/ecx + # var vars/edx: (stack (addr var) 256) + 81 5/subop/subtract %esp 0xc00/imm32 + 68/push 0xc00/imm32/size + 68/push 0/imm32/top + 89/<- %edx 4/r32/esp + # var name/eax: (addr array byte) = lookup(f->name) + (lookup *ecx *(ecx+4)) # Function-name Function-name => eax + # + (write-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) ":\n") + (emit-subx-prologue *(ebp+8)) + # var body/eax: (addr block) = lookup(f->body) + (lookup *(ecx+0x18) *(ecx+0x1c)) # Function-body Function-body => eax + # + (emit-subx-block *(ebp+8) %eax %edx *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + (emit-subx-epilogue *(ebp+8)) + # TODO: validate that *Curr-block-depth and *Curr-local-stack-offset have + # been cleaned up +$emit-subx-function:end: + # . reclaim locals + 81 0/subop/add %esp 0xc08/imm32 + # . restore registers + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +populate-mu-type-offsets-in-inouts: # f: (addr function) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 57/push-edi + # var next-offset/edx: int = 8 + ba/copy-to-edx 8/imm32 + # var curr/ecx: (addr list var) = lookup(f->inouts) + 8b/-> *(ebp+8) 1/r32/ecx + (lookup *(ecx+8) *(ecx+0xc)) # Function-inouts Function-inouts => eax + 89/<- %ecx 0/r32/eax + { +$populate-mu-type-offsets-in-inouts:loop: + 81 7/subop/compare %ecx 0/imm32 + 74/jump-if-= break/disp8 + # var v/ebx: (addr var) = lookup(curr->value) + (lookup *ecx *(ecx+4)) # List-value List-value => eax + 89/<- %ebx 0/r32/eax +#? (lookup *ebx *(ebx+4)) +#? (write-buffered Stderr "setting offset of fn inout ") +#? (write-buffered Stderr %eax) +#? (write-buffered Stderr "@") +#? (write-int32-hex-buffered Stderr %ebx) +#? (write-buffered Stderr " to ") +#? (write-int32-hex-buffered Stderr %edx) +#? (write-buffered Stderr Newline) +#? (flush Stderr) + # v->offset = next-offset + 89/<- *(ebx+0x14) 2/r32/edx # Var-offset + # next-offset += size-of(v) + (size-of %ebx) # => eax + 01/add-to %edx 0/r32/eax + # curr = lookup(curr->next) + (lookup *(ecx+8) *(ecx+0xc)) # List-next List-next => eax + 89/<- %ecx 0/r32/eax + # + eb/jump loop/disp8 + } +$populate-mu-type-offsets-in-inouts:end: + # . restore registers + 5f/pop-to-edi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +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) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 53/push-ebx + 56/push-esi + # esi = stmts + 8b/-> *(ebp+0xc) 6/r32/esi + # + { +$emit-subx-stmt-list:loop: + 81 7/subop/compare %esi 0/imm32 + 0f 84/jump-if-= break/disp32 + # var curr-stmt/ecx: (addr stmt) = lookup(stmts->value) + (lookup *esi *(esi+4)) # List-value List-value => eax + 89/<- %ecx 0/r32/eax + { +$emit-subx-stmt-list:check-for-block: + 81 7/subop/compare *ecx 0/imm32/block # Stmt-tag + 75/jump-if-!= break/disp8 +$emit-subx-stmt-list:block: + (emit-subx-block *(ebp+8) %ecx *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c)) + } + { +$emit-subx-stmt-list:check-for-stmt: + 81 7/subop/compare *ecx 1/imm32/stmt1 # Stmt-tag + 0f 85/jump-if-!= break/disp32 +$emit-subx-stmt-list:stmt1: + { + (is-mu-branch? %ecx) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= break/disp32 +$emit-subx-stmt-list:branch-stmt: + # unconditional return {{{ + { +$emit-subx-stmt-list:return: + # if (!string-equal?(curr-stmt->operation, "return")) break + (lookup *(ecx+4) *(ecx+8)) # Stmt1-operation Stmt1-operation => eax + (string-equal? %eax "return") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= break/disp32 + # + (emit-outputs *(ebp+8) %ecx *(ebp+0x14)) + (emit-cleanup-code-for-non-outputs *(ebp+8) *(ebp+0x10) *(ebp+0x14)) + # emit jump to end of function + # getting at the name of the label is challenging + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "e9/jump ") + # var b/eax: (addr array byte) = fn->body->var->name + 8b/-> *(ebp+0x14) 0/r32/eax + (lookup *(eax+0x18) *(eax+0x1c)) # Function-body Function-body => eax + (lookup *(eax+0xc) *(eax+0x10)) # Block-var Block-var => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) ":break/disp32\n") + e9/jump $emit-subx-stmt-list:clean-up/disp32 + } + # }}} + # unconditional loops {{{ + { + # if (!string-equal?(var->operation, "loop")) break + (lookup *(ecx+4) *(ecx+8)) # Stmt1-operation Stmt1-operation => eax + (string-equal? %eax "loop") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= break/disp32 +$emit-subx-stmt-list:unconditional-loop: + 81 7/subop/compare *(ecx+0xc) 0/imm32 # Stmt1-inouts + # simple unconditional loops without a target + { + 0f 85/jump-if-!= break/disp32 +$emit-subx-stmt-list:zero-arg-unconditional-loop: + (emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth) + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "e9/jump loop/disp32") + (write-buffered *(ebp+8) Newline) + e9/jump $emit-subx-stmt-list:clean-up/disp32 # skip remaining statements; they're dead code + } + # unconditional loops with a target + { + 0f 84/jump-if-= break/disp32 + (emit-subx-cleanup-and-unconditional-nonlocal-branch *(ebp+8) %ecx *(ebp+0x10)) + e9/jump $emit-subx-stmt-list:clean-up/disp32 + } + } + # }}} + # unconditional breaks {{{ + { + # if (!string-equal?(curr-stmt->operation, "break")) break + (lookup *(ecx+4) *(ecx+8)) # Stmt1-operation Stmt1-operation => eax + (string-equal? %eax "break") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= break/disp32 +$emit-subx-stmt-list:unconditional-break: + 81 7/subop/compare *(ecx+0xc) 0/imm32 # Stmt1-inouts + # simple unconditional breaks without a target + 0f 84/jump-if-= $emit-subx-stmt-list:emit-cleanup/disp32 # easy: just skip remaining statements + # unconditional breaks with a target + (emit-subx-cleanup-and-unconditional-nonlocal-branch *(ebp+8) %ecx *(ebp+0x10)) + e9/jump $emit-subx-stmt-list:clean-up/disp32 + } + # }}} + # simple conditional branches without a target {{{ + 81 7/subop/compare *(ecx+0xc) 0/imm32 # Stmt1-inouts + { + 0f 85/jump-if-!= break/disp32 +$emit-subx-stmt-list:zero-arg-conditional-branch: + # var old-block-depth/ebx: int = Curr-block-depth - 1 + 8b/-> *Curr-block-depth 3/r32/ebx + # cleanup prologue + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "{\n") + ff 0/subop/increment *Curr-block-depth + # + (emit-reverse-break *(ebp+8) %ecx) + # clean up until old block depth + (emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) %ebx) + # var target-block-depth/ebx: int = Curr-block-depth - 1 + 4b/decrement-ebx + # emit jump to target block + (lookup *(ecx+4) *(ecx+8)) # Stmt1-operation Stmt1-operation => eax + (string-starts-with? %eax "break") # => eax + 3d/compare-eax-and 0/imm32/false + { + 74/jump-if-= break/disp8 + (emit-unconditional-jump-to-depth *(ebp+8) *(ebp+0x10) %ebx "break") + } + 3d/compare-eax-and 0/imm32/false # just in case the function call modified flags + { + 75/jump-if-!= break/disp8 + (emit-unconditional-jump-to-depth *(ebp+8) *(ebp+0x10) %ebx "loop") + } + # cleanup epilogue + ff 1/subop/decrement *Curr-block-depth + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "}\n") + # continue + e9/jump $emit-subx-stmt-list:continue/disp32 + } + # }}} + # conditional branches with an explicit target {{{ + { + 0f 84/jump-if-= break/disp32 +$emit-subx-stmt-list:conditional-branch-with-target: + # cleanup prologue + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "{\n") + ff 0/subop/increment *Curr-block-depth + # + (emit-reverse-break *(ebp+8) %ecx) + (emit-subx-cleanup-and-unconditional-nonlocal-branch *(ebp+8) %ecx *(ebp+0x10)) + # cleanup epilogue + ff 1/subop/decrement *Curr-block-depth + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "}\n") + # continue + e9/jump $emit-subx-stmt-list:continue/disp32 + } + # }}} + } +$emit-subx-stmt-list:1-to-1: + (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c)) + e9/jump $emit-subx-stmt-list:continue/disp32 + } + { +$emit-subx-stmt-list:check-for-var-def: + 81 7/subop/compare *ecx 2/imm32/var-def # Stmt-tag + 75/jump-if-!= break/disp8 +$emit-subx-stmt-list:var-def: + (emit-subx-var-def *(ebp+8) %ecx) + (push *(ebp+0x10) *(ecx+4)) # Vardef-var + (push *(ebp+0x10) *(ecx+8)) # Vardef-var + (push *(ebp+0x10) 0) # Live-var-register-spilled = 0 for vars on the stack + # + eb/jump $emit-subx-stmt-list:continue/disp8 + } + { +$emit-subx-stmt-list:check-for-reg-var-def: + 81 7/subop/compare *ecx 3/imm32/reg-var-def # Stmt-tag + 0f 85/jump-if-!= break/disp32 +$emit-subx-stmt-list:reg-var-def: + # TODO: ensure that there's exactly one output + (push-output-and-maybe-emit-spill *(ebp+8) %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c)) + # emit the instruction as usual + (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c)) + # + eb/jump $emit-subx-stmt-list:continue/disp8 + } +$emit-subx-stmt-list:continue: + # TODO: raise an error on unrecognized Stmt-tag + (lookup *(esi+8) *(esi+0xc)) # List-next List-next => eax + 89/<- %esi 0/r32/eax + e9/jump loop/disp32 + } +$emit-subx-stmt-list:emit-cleanup: + (emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth) +$emit-subx-stmt-list:clean-up: + (clean-up-stack-offset-state *(ebp+0x10) *Curr-block-depth) + (clean-up-blocks *(ebp+0x10) *Curr-block-depth *(ebp+0x14)) +$emit-subx-stmt-list:end: + # . restore registers + 5e/pop-to-esi + 5b/pop-to-ebx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# 'later-stmts' includes 'stmt', but will behave the same even without it; reg-var-def stmts are guaranteed not to write to function outputs. +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) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + # ecx = stmt + 8b/-> *(ebp+0xc) 1/r32/ecx + # var sv/eax: (addr stmt-var) = lookup(curr-stmt->outputs) + (lookup *(ecx+0x14) *(ecx+0x18)) # Regvardef-outputs Regvardef-outputs => eax + # TODO: assert !sv->is-deref? + # var v/ecx: (addr var) = lookup(sv->value) + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %ecx 0/r32/eax + # v->block-depth = *Curr-block-depth + 8b/-> *Curr-block-depth 0/r32/eax + 89/<- *(ecx+0x10) 0/r32/eax # Var-block-depth +#? (write-buffered Stderr "var ") +#? (lookup *ecx *(ecx+4)) +#? (write-buffered Stderr %eax) +#? (write-buffered Stderr " at depth ") +#? (write-int32-hex-buffered Stderr *(ecx+0x10)) +#? (write-buffered Stderr Newline) +#? (flush Stderr) + # ensure that v is in a register + 81 7/subop/compare *(ecx+0x18) 0/imm32 # Var-register + 0f 84/jump-if-= $push-output-and-maybe-emit-spill:abort/disp32 + # var emit-spill?/edx: boolean = not-yet-spilled-this-block? && will-not-write-some-register?(fn) + (not-yet-spilled-this-block? %ecx *(ebp+0x10)) # => eax + 89/<- %edx 0/r32/eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32 + (will-not-write-some-register? %ecx *(ebp+0x14) *(ebp+0x18)) # => eax + 89/<- %edx 0/r32/eax + # check emit-spill? + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32 + # TODO: assert(size-of(output) == 4) + # *Curr-local-stack-offset -= 4 + 81 5/subop/subtract *Curr-local-stack-offset 4/imm32 + # emit spill + (lookup *(ecx+0x18) *(ecx+0x1c)) # Var-register Var-register => eax + (emit-push-register *(ebp+8) %eax) +$push-output-and-maybe-emit-spill:push: + 8b/-> *(ebp+0xc) 1/r32/ecx + (lookup *(ecx+0x14) *(ecx+0x18)) # Regvardef-outputs Regvardef-outputs => eax + # push(vars, {sv->value, emit-spill?}) + (push *(ebp+0x10) *eax) # Stmt-var-value + (push *(ebp+0x10) *(eax+4)) # Stmt-var-value + (push *(ebp+0x10) %edx) +$push-output-and-maybe-emit-spill:end: + # . restore registers + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$push-output-and-maybe-emit-spill:abort: + # error("var '" var->name "' initialized from an instruction must live in a register\n") + (write-buffered *(ebp+0x1c) "var '") + (write-buffered *(ebp+0x1c) *eax) # Var-name + (write-buffered *(ebp+0x1c) "' initialized from an instruction must live in a register\n") + (flush *(ebp+0x1c)) + (stop *(ebp+0x20) 1) + # never gets here + +emit-subx-cleanup-and-unconditional-nonlocal-branch: # out: (addr buffered-file), stmt: (addr stmt1), vars: (addr stack live-var) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + # ecx = stmt + 8b/-> *(ebp+0xc) 1/r32/ecx + # var target/eax: (addr array byte) = curr-stmt->inouts->value->name + (lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + # clean up until target block + (emit-cleanup-code-until-target *(ebp+8) *(ebp+0x10) %eax) + # emit jump to target block + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "e9/jump ") + (write-buffered *(ebp+8) %eax) + (lookup *(ecx+4) *(ecx+8)) # Stmt1-operation Stmt1-operation => eax + (string-starts-with? %eax "break") + 3d/compare-eax-and 0/imm32/false + { + 74/jump-if-= break/disp8 + (write-buffered *(ebp+8) ":break/disp32\n") + eb/jump $emit-subx-cleanup-and-unconditional-nonlocal-branch:end/disp8 + } + (write-buffered *(ebp+8) ":loop/disp32\n") +$emit-subx-cleanup-and-unconditional-nonlocal-branch:end: + # . restore registers + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +emit-outputs: # out: (addr buffered-file), return-stmt: (addr stmt1), fn: (addr function) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 56/push-esi + 57/push-edi + # var curr-inout/esi: (addr stmt-var) = return-stmt->inouts + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *(eax+0xc) *(eax+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 89/<- %esi 0/r32/eax + # var curr-output/edi: (addr list var) = fn->outputs + 8b/-> *(ebp+0x10) 0/r32/eax + (lookup *(eax+0x10) *(eax+0x14)) # Function-outputs Function-outputs => eax + 89/<- %edi 0/r32/eax + { +$emit-outputs:loop: + 81 7/subop/compare %esi 0/imm32 + 0f 84/jump-if-= break/disp32 + # emit copy to output register + # var curr-output-register/ecx: (addr array byte) = curr-output->value->register + (lookup *edi *(edi+4)) # List-value List-value => eax + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + 89/<- %ecx 0/r32/eax + # if curr-output-register starts with "x", emit a floating-point copy + 8a/copy-byte *(ecx+4) 0/r32/AL + 81 4/subop/and %eax 0xff/imm32 + 3d/compare-eax-and 0x78/imm32/x + { + 75/jump-if-!= break/disp8 + (emit-float-output *(ebp+8) %esi %ecx) + eb/jump $emit-outputs:continue/disp8 + } + # otherwise emit an int copy + (emit-int-output *(ebp+8) %esi %ecx) +$emit-outputs:continue: + # curr-inout = curr-inout->next + (lookup *(esi+8) *(esi+0xc)) # Stmt-var-next Stmt-var-next => eax + 89/<- %esi 0/r32/eax + # curr-output = curr-output->next + (lookup *(edi+8) *(edi+0xc)) # List-next List-next => eax + 89/<- %edi 0/r32/eax + # + e9/jump loop/disp32 + } +$emit-outputs:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +emit-int-output: # out: (addr buffered-file), return-var: (addr stmt-var), dest-reg: (addr array byte) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + # ecx = return-var->value + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %ecx 0/r32/eax + # if curr-var is a literal, emit copy of a literal to the output + (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + (is-simple-mu-type? %eax 0) # literal => eax + { + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= break/disp32 + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "c7 0/subop/copy %") + (write-buffered *(ebp+8) *(ebp+0x10)) + (write-buffered *(ebp+8) " ") + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) "/imm32\n") + e9/jump $emit-int-output:end/disp32 + } + # otherwise emit an integer copy + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "8b/->") + (emit-subx-var-as-rm32 *(ebp+8) *(ebp+0xc)) + (write-buffered *(ebp+8) " ") + (get Mu-registers *(ebp+0x10) 0xc "Mu-registers") # => eax + (write-int32-hex-buffered *(ebp+8) *eax) + (write-buffered *(ebp+8) "/r32\n") +$emit-int-output:end: + # . restore registers + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +emit-float-output: # out: (addr buffered-file), return-var: (addr stmt-var), dest-reg: (addr array byte) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + # + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "f3 0f 10/->") + (emit-subx-var-as-rm32 *(ebp+8) *(ebp+0xc)) + (write-buffered *(ebp+8) " ") + (get Mu-registers *(ebp+0x10) 0xc "Mu-registers") # => eax + (write-int32-hex-buffered *(ebp+8) *eax) + (write-buffered *(ebp+8) "/x32\n") +$emit-float-output:end: + # . restore registers + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +is-mu-branch?: # stmt: (addr stmt1) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # ecx = lookup(stmt->operation) + 8b/-> *(ebp+8) 1/r32/ecx + (lookup *(ecx+4) *(ecx+8)) # Stmt1-operation Stmt1-operation => eax + 89/<- %ecx 0/r32/eax + # if (stmt->operation starts with "loop") return true + (string-starts-with? %ecx "loop") # => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-not-equal $is-mu-branch?:end/disp8 + # if (stmt->operation starts with "break") return true + (string-starts-with? %ecx "break") # => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-not-equal $is-mu-branch?:end/disp8 + # otherwise return (stmt->operation starts with "return") + (string-starts-with? %ecx "return") # => eax +$is-mu-branch?:end: + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +emit-reverse-break: # out: (addr buffered-file), stmt: (addr stmt1) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + # eax = stmt + 8b/-> *(ebp+0xc) 0/r32/eax + # + (lookup *(eax+4) *(eax+8)) # Stmt1-operation Stmt1-operation => eax + (get Reverse-branch %eax 0x10 "reverse-branch: ") # => eax: (addr handle array byte) + (emit-indent *(ebp+8) *Curr-block-depth) + (lookup *eax *(eax+4)) # => eax + (write-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) " break/disp32\n") +$emit-reverse-break:end: + # . restore registers + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +== data + +# Table from Mu branch instructions to the reverse SubX opcodes for them. +Reverse-branch: # (table (handle array byte) (handle array byte)) + # a table is a stream + 0x1c0/imm32/write + 0/imm32/read + 0x1c0/imm32/size + # data + 0x11/imm32/alloc-id _string-break-if-=/imm32 0x11/imm32/alloc-id _string_0f_85_jump_label/imm32 + 0x11/imm32/alloc-id _string-loop-if-=/imm32 0x11/imm32/alloc-id _string_0f_85_jump_label/imm32 + 0x11/imm32/alloc-id _string-break-if-!=/imm32 0x11/imm32/alloc-id _string_0f_84_jump_label/imm32 + 0x11/imm32/alloc-id _string-loop-if-!=/imm32 0x11/imm32/alloc-id _string_0f_84_jump_label/imm32 + 0x11/imm32/alloc-id _string-break-if-</imm32 0x11/imm32/alloc-id _string_0f_8d_jump_label/imm32 + 0x11/imm32/alloc-id _string-loop-if-</imm32 0x11/imm32/alloc-id _string_0f_8d_jump_label/imm32 + 0x11/imm32/alloc-id _string-break-if->/imm32 0x11/imm32/alloc-id _string_0f_8e_jump_label/imm32 + 0x11/imm32/alloc-id _string-loop-if->/imm32 0x11/imm32/alloc-id _string_0f_8e_jump_label/imm32 + 0x11/imm32/alloc-id _string-break-if-<=/imm32 0x11/imm32/alloc-id _string_0f_8f_jump_label/imm32 + 0x11/imm32/alloc-id _string-loop-if-<=/imm32 0x11/imm32/alloc-id _string_0f_8f_jump_label/imm32 + 0x11/imm32/alloc-id _string-break-if->=/imm32 0x11/imm32/alloc-id _string_0f_8c_jump_label/imm32 + 0x11/imm32/alloc-id _string-loop-if->=/imm32 0x11/imm32/alloc-id _string_0f_8c_jump_label/imm32 + 0x11/imm32/alloc-id _string-break-if-addr</imm32 0x11/imm32/alloc-id _string_0f_83_jump_label/imm32 + 0x11/imm32/alloc-id _string-loop-if-addr</imm32 0x11/imm32/alloc-id _string_0f_83_jump_label/imm32 + 0x11/imm32/alloc-id _string-break-if-addr>/imm32 0x11/imm32/alloc-id _string_0f_86_jump_label/imm32 + 0x11/imm32/alloc-id _string-loop-if-addr>/imm32 0x11/imm32/alloc-id _string_0f_86_jump_label/imm32 + 0x11/imm32/alloc-id _string-break-if-addr<=/imm32 0x11/imm32/alloc-id _string_0f_87_jump_label/imm32 + 0x11/imm32/alloc-id _string-loop-if-addr<=/imm32 0x11/imm32/alloc-id _string_0f_87_jump_label/imm32 + 0x11/imm32/alloc-id _string-break-if-addr>=/imm32 0x11/imm32/alloc-id _string_0f_82_jump_label/imm32 + 0x11/imm32/alloc-id _string-loop-if-addr>=/imm32 0x11/imm32/alloc-id _string_0f_82_jump_label/imm32 + 0x11/imm32/alloc-id _string-break-if-float</imm32 0x11/imm32/alloc-id _string_0f_83_jump_label/imm32 + 0x11/imm32/alloc-id _string-loop-if-float</imm32 0x11/imm32/alloc-id _string_0f_83_jump_label/imm32 + 0x11/imm32/alloc-id _string-break-if-float>/imm32 0x11/imm32/alloc-id _string_0f_86_jump_label/imm32 + 0x11/imm32/alloc-id _string-loop-if-float>/imm32 0x11/imm32/alloc-id _string_0f_86_jump_label/imm32 + 0x11/imm32/alloc-id _string-break-if-float<=/imm32 0x11/imm32/alloc-id _string_0f_87_jump_label/imm32 + 0x11/imm32/alloc-id _string-loop-if-float<=/imm32 0x11/imm32/alloc-id _string_0f_87_jump_label/imm32 + 0x11/imm32/alloc-id _string-break-if-float>=/imm32 0x11/imm32/alloc-id _string_0f_82_jump_label/imm32 + 0x11/imm32/alloc-id _string-loop-if-float>=/imm32 0x11/imm32/alloc-id _string_0f_82_jump_label/imm32 + +== code + +emit-unconditional-jump-to-depth: # out: (addr buffered-file), vars: (addr stack live-var), depth: int, label-suffix: (addr array byte) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + # ecx = vars + 8b/-> *(ebp+0xc) 1/r32/ecx + # var eax: int = vars->top + 8b/-> *ecx 0/r32/eax + # var curr/esi: (addr handle var) = &vars->data[vars->top - 12] + 8d/copy-address *(ecx+eax-4) 6/r32/esi # vars + 8 + vars->top - 12/Live-var-size + # var min/ecx: (addr handle var) = vars->data + 8d/copy-address *(ecx+8) 1/r32/ecx + # edx = depth + 8b/-> *(ebp+0x10) 2/r32/edx + { +$emit-unconditional-jump-to-depth:loop: + # if (curr < min) break + 39/compare %esi 1/r32/ecx + 0f 82/jump-if-addr< break/disp32 + # var v/ebx: (addr var) = lookup(*curr) + (lookup *esi *(esi+4)) # => eax + 89/<- %ebx 0/r32/eax + # if (v->block-depth < until-block-depth) break + 39/compare *(ebx+0x10) 2/r32/edx # Var-block-depth + 0f 8c/jump-if-< break/disp32 + { +$emit-unconditional-jump-to-depth:check: + # if v->block-depth != until-block-depth, continue + 39/compare *(ebx+0x10) 2/r32/edx # Var-block-depth + 0f 85/jump-if-!= break/disp32 +$emit-unconditional-jump-to-depth:depth-found: + # if v is not a literal, continue + (size-of %ebx) # => eax + 3d/compare-eax-and 0/imm32 + 0f 85/jump-if-!= break/disp32 +$emit-unconditional-jump-to-depth:label-found: + # emit unconditional jump, then return + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "e9/jump ") + (lookup *ebx *(ebx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) ":") + (write-buffered *(ebp+8) *(ebp+0x14)) + (write-buffered *(ebp+8) "/disp32\n") + eb/jump $emit-unconditional-jump-to-depth:end/disp8 + } + # curr -= 12 + 81 5/subop/subtract %esi 0xc/imm32 + e9/jump loop/disp32 + } + # TODO: error if no label at 'depth' was found +$emit-unconditional-jump-to-depth:end: + # . restore registers + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# emit clean-up code for 'vars' until some block depth +# doesn't actually modify 'vars' so we need traverse manually inside the stack +emit-cleanup-code-until-depth: # out: (addr buffered-file), vars: (addr stack live-var), until-block-depth: int + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi +#? (write-buffered Stderr "--- cleanup\n") +#? (flush Stderr) + # ecx = vars + 8b/-> *(ebp+0xc) 1/r32/ecx + # var esi: int = vars->top + 8b/-> *ecx 6/r32/esi + # var curr/esi: (addr handle var) = &vars->data[vars->top - 12] + 8d/copy-address *(ecx+esi-4) 6/r32/esi # vars + 8 + vars->top - 12/Live-var-size + # var min/ecx: (addr handle var) = vars->data + 81 0/subop/add %ecx 8/imm32 + # edx = until-block-depth + 8b/-> *(ebp+0x10) 2/r32/edx + { +$emit-cleanup-code-until-depth:loop: + # if (curr < min) break + 39/compare %esi 1/r32/ecx + 0f 82/jump-if-addr< break/disp32 + # var v/ebx: (addr var) = lookup(*curr) + (lookup *esi *(esi+4)) # => eax + 89/<- %ebx 0/r32/eax +#? (lookup *ebx *(ebx+4)) # Var-name +#? (write-buffered Stderr "var ") +#? (write-buffered Stderr %eax) +#? (write-buffered Stderr Newline) +#? (flush Stderr) + # if (v->block-depth < until-block-depth) break + 39/compare *(ebx+0x10) 2/r32/edx # Var-block-depth + 0f 8c/jump-if-< break/disp32 + # if v is in a register + 81 7/subop/compare *(ebx+0x18) 0/imm32 # Var-register + { + 0f 84/jump-if-= break/disp32 + { +$emit-cleanup-code-until-depth:check-for-previous-spill: + 8b/-> *(esi+8) 0/r32/eax # Live-var-register-spilled + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 +$emit-cleanup-code-until-depth:reclaim-var-in-register: + (lookup *(ebx+0x18) *(ebx+0x1c)) # Var-register Var-register => eax + (emit-pop-register *(ebp+8) %eax) + } + eb/jump $emit-cleanup-code-until-depth:continue/disp8 + } + # otherwise v is on the stack + { + 75/jump-if-!= break/disp8 +$emit-cleanup-code-until-depth:var-on-stack: + (size-of %ebx) # => eax + # don't emit code for labels + 3d/compare-eax-and 0/imm32 + 74/jump-if-= break/disp8 +$emit-cleanup-code-until-depth:reclaim-var-on-stack: + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "81 0/subop/add %esp ") + (write-int32-hex-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) "/imm32\n") + } +$emit-cleanup-code-until-depth:continue: + # curr -= 12 + 81 5/subop/subtract %esi 0xc/imm32 + e9/jump loop/disp32 + } +$emit-cleanup-code-until-depth:end: + # . restore registers + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# emit clean-up code for 'vars' that don't conflict with output registers +# doesn't actually modify 'vars' so we need traverse manually inside the stack +emit-cleanup-code-for-non-outputs: # out: (addr buffered-file), vars: (addr stack live-var), fn: (addr function) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + 57/push-edi + # ecx = vars + 8b/-> *(ebp+0xc) 1/r32/ecx + # var esi: int = vars->top + 8b/-> *ecx 6/r32/esi + # var curr/esi: (addr handle var) = &vars->data[vars->top - 12] + 8d/copy-address *(ecx+esi-4) 6/r32/esi # vars + 8 + vars->top - 12/Live-var-size + # var min/ecx: (addr handle var) = vars->data + 81 0/subop/add %ecx 8/imm32 + { +$emit-cleanup-code-for-non-outputs:loop: + # if (curr < min) break + 39/compare %esi 1/r32/ecx + 0f 82/jump-if-addr< break/disp32 + # var v/ebx: (addr var) = lookup(*curr) + (lookup *esi *(esi+4)) # => eax + 89/<- %ebx 0/r32/eax + # if v is in a register + 81 7/subop/compare *(ebx+0x18) 0/imm32 # Var-register + { + 0f 84/jump-if-= break/disp32 + { +$emit-cleanup-code-for-non-outputs:check-for-previous-spill: + 8b/-> *(esi+8) 0/r32/eax # Live-var-register-spilled + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= break/disp32 +$emit-cleanup-code-for-non-outputs:reclaim-var-in-register: + # var reg/edi: (addr array name) = v->register + (lookup *(ebx+0x18) *(ebx+0x1c)) # Var-register Var-register => eax + 89/<- %edi 0/r32/eax + # if reg is not in function outputs, emit a pop + (reg-in-function-outputs? *(ebp+0x10) %edi) # => eax + 3d/compare-eax-and 0/imm32/false + { + 75/jump-if-!= break/disp8 + (emit-pop-register *(ebp+8) %edi) + eb/jump $emit-cleanup-code-for-non-outputs:reclaim-var-in-register-done/disp8 + } + # otherwise just drop it from the stack + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "81 0/subop/add %esp 4/imm32\n") + } +$emit-cleanup-code-for-non-outputs:reclaim-var-in-register-done: + eb/jump $emit-cleanup-code-for-non-outputs:continue/disp8 + } + # otherwise v is on the stack + { + 75/jump-if-!= break/disp8 +$emit-cleanup-code-for-non-outputs:var-on-stack: + (size-of %ebx) # => eax + # don't emit code for labels + 3d/compare-eax-and 0/imm32 + 74/jump-if-= break/disp8 +$emit-cleanup-code-for-non-outputs:reclaim-var-on-stack: + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "81 0/subop/add %esp ") + (write-int32-hex-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) "/imm32\n") + } +$emit-cleanup-code-for-non-outputs:continue: + # curr -= 12 + 81 5/subop/subtract %esi 0xc/imm32 + e9/jump loop/disp32 + } +$emit-cleanup-code-for-non-outputs:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +emit-push-register: # out: (addr buffered-file), reg: (addr array byte) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # eax = reg + 8b/-> *(ebp+0xc) 0/r32/eax + # var prefix/eax: byte = reg->data[0] + 8a/copy-byte *(eax+4) 0/r32/AL + 81 4/subop/and %eax 0xff/imm32 + # if (prefix == 'x') push xmm register + { + 3d/compare-eax-and 0x78/imm32/x + 0f 85/jump-if-!= break/disp32 + # TODO validate register + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "81 5/subop/subtract %esp 4/imm32\n") + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "f3 0f 11/<- *esp ") + # var prefix/eax: byte = reg->data[3] + 8b/-> *(ebp+0xc) 0/r32/eax + 8a/copy-byte *(eax+7) 0/r32/AL + 81 4/subop/and %eax 0xff/imm32 + (write-byte-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) "/x32\n") + e9/jump $emit-push-register:end/disp32 + } + # otherwise push gp register + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "ff 6/subop/push %") + (write-buffered *(ebp+8) *(ebp+0xc)) + (write-buffered *(ebp+8) Newline) +$emit-push-register:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +emit-pop-register: # out: (addr buffered-file), reg: (addr array byte) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + # eax = reg + 8b/-> *(ebp+0xc) 0/r32/eax + # var prefix/eax: byte = reg->data[0] + 8a/copy-byte *(eax+4) 0/r32/AL + 81 4/subop/and %eax 0xff/imm32 + # if (prefix == 'x') pop to xmm register + { + 3d/compare-eax-and 0x78/imm32/x + 0f 85/jump-if-!= break/disp32 + # TODO validate register + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "f3 0f 10/-> *esp ") + # var prefix/eax: byte = reg->data[3] + 8b/-> *(ebp+0xc) 0/r32/eax + 8a/copy-byte *(eax+7) 0/r32/AL + 81 4/subop/and %eax 0xff/imm32 + (write-byte-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) "/x32\n") + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "81 0/subop/add %esp 4/imm32\n") + e9/jump $emit-pop-register:end/disp32 + } + # otherwise pop to gp register + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "8f 0/subop/pop %") + (write-buffered *(ebp+8) *(ebp+0xc)) + (write-buffered *(ebp+8) Newline) +$emit-pop-register:end: + # . restore registers + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# emit clean-up code for 'vars' until a given label is encountered +# doesn't actually modify 'vars' so we need traverse manually inside the stack +emit-cleanup-code-until-target: # out: (addr buffered-file), vars: (addr stack live-var), until-block-label: (addr array byte) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + # ecx = vars + 8b/-> *(ebp+0xc) 1/r32/ecx + # var eax: int = vars->top + 8b/-> *ecx 0/r32/eax + # var curr/edx: (addr handle var) = &vars->data[vars->top - 12] + 8d/copy-address *(ecx+eax-4) 2/r32/edx # vars + 8 + vars->top - 12/Live-var-size + # var min/ecx: (addr handle var) = vars->data + 81 0/subop/add %ecx 8/imm32 + { +$emit-cleanup-code-until-target:loop: + # if (curr < min) break + 39/compare %edx 1/r32/ecx + 0f 82/jump-if-addr< break/disp32 + # var v/ebx: (handle var) = lookup(*curr) + (lookup *edx *(edx+4)) # => eax + 89/<- %ebx 0/r32/eax + # if (v->name == until-block-label) break + (lookup *ebx *(ebx+4)) # Var-name Var-name => eax + (string-equal? %eax *(ebp+0x10)) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= break/disp32 + # if v is in a register + 81 7/subop/compare *(ebx+0x18) 0/imm32 # Var-register + { + 0f 84/jump-if-= break/disp32 + { +$emit-cleanup-code-until-target:check-for-previous-spill: + 8b/-> *(edx+8) 0/r32/eax # Live-var-register-spilled + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 +$emit-cleanup-code-until-target:reclaim-var-in-register: + (lookup *(ebx+0x18) *(ebx+0x1c)) # Var-register Var-register => eax + (emit-pop-register *(ebp+8) %eax) + } + eb/jump $emit-cleanup-code-until-target:continue/disp8 + } + # otherwise v is on the stack + { + 75/jump-if-!= break/disp8 +$emit-cleanup-code-until-target:reclaim-var-on-stack: + (size-of %ebx) # => eax + # don't emit code for labels + 3d/compare-eax-and 0/imm32 + 74/jump-if-= break/disp8 + # + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "81 0/subop/add %esp ") + (write-int32-hex-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) "/imm32\n") + } +$emit-cleanup-code-until-target:continue: + # curr -= 12 + 81 5/subop/subtract %edx 0xc/imm32 + e9/jump loop/disp32 + } +$emit-cleanup-code-until-target:end: + # . restore registers + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# update Curr-local-stack-offset assuming vars until some block depth are popped +# doesn't actually modify 'vars', so we need traverse manually inside the stack +clean-up-stack-offset-state: # vars: (addr stack live-var), until-block-depth: int + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + # ecx = vars + 8b/-> *(ebp+8) 1/r32/ecx + # var esi: int = vars->top + 8b/-> *ecx 6/r32/esi + # var curr/esi: (addr handle var) = &vars->data[vars->top - 12] + 8d/copy-address *(ecx+esi-4) 6/r32/esi # vars + 8 + vars->top - 12/Live-var-size + # var min/ecx: (addr handle var) = vars->data + 81 0/subop/add %ecx 8/imm32 + # edx = until-block-depth + 8b/-> *(ebp+0xc) 2/r32/edx + { +$clean-up-stack-offset-state:loop: + # if (curr < min) break + 39/compare %esi 1/r32/ecx + 0f 82/jump-if-addr< break/disp32 + # var v/ebx: (addr var) = lookup(*curr) + (lookup *esi *(esi+4)) # => eax + 89/<- %ebx 0/r32/eax + # if (v->block-depth < until-block-depth) break + 39/compare *(ebx+0x10) 2/r32/edx # Var-block-depth + 0f 8c/jump-if-< break/disp32 + # if v is in a register + 81 7/subop/compare *(ebx+0x18) 0/imm32 # Var-register + { + 0f 84/jump-if-= break/disp32 + { +$clean-up-stack-offset-state:check-for-previous-spill: + 8b/-> *(esi+8) 0/r32/eax # Live-var-register-spilled + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 +$clean-up-stack-offset-state:reclaim-var-in-register: + 81 0/subop/add *Curr-local-stack-offset 4/imm32 + } + eb/jump $clean-up-stack-offset-state:continue/disp8 + } + # otherwise v is on the stack + { + 75/jump-if-!= break/disp8 +$clean-up-stack-offset-state:var-on-stack: + (size-of %ebx) # => eax + 01/add-to *Curr-local-stack-offset 0/r32/eax + } +$clean-up-stack-offset-state:continue: + # curr -= 12 + 81 5/subop/subtract %esi 0xc/imm32 + e9/jump loop/disp32 + } +$clean-up-stack-offset-state:end: + # . restore registers + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# Return true if there isn't a variable in 'vars' with the same block-depth +# and register as 'v'. +# 'v' is guaranteed not to be within 'vars'. +not-yet-spilled-this-block?: # v: (addr var), vars: (addr stack live-var) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + 57/push-edi + # ecx = vars + 8b/-> *(ebp+0xc) 1/r32/ecx + # var eax: int = vars->top + 8b/-> *ecx 0/r32/eax + # var curr/edx: (addr handle var) = &vars->data[vars->top - 12] + 8d/copy-address *(ecx+eax-4) 2/r32/edx # vars + 8 + vars->top - 12/Live-var-size + # var min/ecx: (addr handle var) = vars->data + 8d/copy-address *(ecx+8) 1/r32/ecx + # var depth/ebx: int = v->block-depth + 8b/-> *(ebp+8) 3/r32/ebx + 8b/-> *(ebx+0x10) 3/r32/ebx # Var-block-depth + # var needle/esi: (addr array byte) = v->register + 8b/-> *(ebp+8) 6/r32/esi + (lookup *(esi+0x18) *(esi+0x1c)) # Var-register Var-register => eax + 89/<- %esi 0/r32/eax + { +$not-yet-spilled-this-block?:loop: + # if (curr < min) break + 39/compare %edx 1/r32/ecx + 0f 82/jump-if-addr< break/disp32 + # var cand/edi: (addr var) = lookup(*curr) + (lookup *edx *(edx+4)) # => eax + 89/<- %edi 0/r32/eax + # if (cand->block-depth < depth) break + 39/compare *(edi+0x10) 3/r32/ebx # Var-block-depth + 0f 8c/jump-if-< break/disp32 + # var cand-reg/edi: (array array byte) = cand->reg + (lookup *(edi+0x18) *(edi+0x1c)) # Var-register Var-register => eax + 89/<- %edi 0/r32/eax + # if (cand-reg == null) continue + { +$not-yet-spilled-this-block?:check-reg: + 81 7/subop/compare %edi 0/imm32 + 0f 84/jump-if-= break/disp32 + # if (cand-reg == needle) return true + (string-equal? %esi %edi) # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 +$not-yet-spilled-this-block?:return-false: + b8/copy-to-eax 0/imm32/false + eb/jump $not-yet-spilled-this-block?:end/disp8 + } +$not-yet-spilled-this-block?:continue: + # curr -= 12 + 81 5/subop/subtract %edx 0xc/imm32 + e9/jump loop/disp32 + } +$not-yet-spilled-this-block?:return-true: + # return true + b8/copy-to-eax 1/imm32/true +$not-yet-spilled-this-block?:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# could the register of 'v' ever be written to by one of the vars in fn-outputs? +will-not-write-some-register?: # v: (addr var), stmts: (addr list stmt), fn: (addr function) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # eax = v + 8b/-> *(ebp+8) 0/r32/eax + # var reg/eax: (addr array byte) = lookup(v->register) + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + # var target/eax: (addr var) = find-register(fn-outputs, reg) + (find-register *(ebp+0x10) %eax) # => eax + # if (target == 0) return true + { + 3d/compare-eax-and 0/imm32 + 75/jump-if-!= break/disp8 + b8/copy-to-eax 1/imm32/true + eb/jump $will-not-write-some-register?:end/disp8 + } + # return !assigns-in-stmts?(stmts, target) + (assigns-in-stmts? *(ebp+0xc) %eax) # => eax + 3d/compare-eax-and 0/imm32/false + # assume: true = 1, so no need to mask with 0x000000ff + 0f 94/set-if-= %al +$will-not-write-some-register?:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# return fn output with matching register +# always returns false if 'reg' is null +find-register: # fn: (addr function), reg: (addr array byte) -> result/eax: (addr var) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # var curr/ecx: (addr list var) = lookup(fn->outputs) + 8b/-> *(ebp+8) 1/r32/ecx + (lookup *(ecx+0x10) *(ecx+0x14)) # Function-outputs Function-outputs => eax + 89/<- %ecx 0/r32/eax + { +$find-register:loop: + # if (curr == 0) break + 81 7/subop/compare %ecx 0/imm32 + 74/jump-if-= break/disp8 + # eax = curr->value->register + (lookup *ecx *(ecx+4)) # List-value List-value => eax + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + # if (eax == reg) return curr->value +$find-register:compare: + (string-equal? *(ebp+0xc) %eax) # => eax + { + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 +$find-register:found: + (lookup *ecx *(ecx+4)) # List-value List-value => eax + eb/jump $find-register:end/disp8 + } + # curr = lookup(curr->next) + (lookup *(ecx+8) *(ecx+0xc)) # List-next List-next => eax + 89/<- %ecx 0/r32/eax + # + eb/jump loop/disp8 + } +$find-register:end: + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +assigns-in-stmts?: # stmts: (addr list stmt), v: (addr var) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # var curr/ecx: (addr list stmt) = stmts + 8b/-> *(ebp+8) 1/r32/ecx + { + # if (curr == 0) break + 81 7/subop/compare %ecx 0/imm32 + 74/jump-if-= break/disp8 + # if assigns-in-stmt?(curr->value, v) return true + (lookup *ecx *(ecx+4)) # List-value List-value => eax + (assigns-in-stmt? %eax *(ebp+0xc)) # => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 + # curr = lookup(curr->next) + (lookup *(ecx+8) *(ecx+0xc)) # List-next List-next => eax + 89/<- %ecx 0/r32/eax + # + eb/jump loop/disp8 + } +$assigns-in-stmts?:end: + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +assigns-in-stmt?: # stmt: (addr stmt), v: (addr var) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # ecx = stmt + 8b/-> *(ebp+8) 1/r32/ecx + # if stmt is a stmt1, return assigns-in-stmt-vars?(stmt->outputs, v) + { + 81 7/subop/compare *ecx 1/imm32/stmt1 # Stmt-tag + 75/jump-if-!= break/disp8 + (lookup *(ecx+0x14) *(ecx+0x18)) # Stmt1-outputs Stmt1-outputs => eax + (assigns-in-stmt-vars? %eax *(ebp+0xc)) # => eax + eb/jump $assigns-in-stmt?:end/disp8 + } + # if stmt is a block, return assigns-in-stmts?(stmt->stmts, v) + { + 81 7/subop/compare *ecx 0/imm32/block # Stmt-tag + 75/jump-if-!= break/disp8 + (lookup *(ecx+4) *(ecx+8)) # Block-stmts Block-stmts => eax + (assigns-in-stmts? %eax *(ebp+0xc)) # => eax + eb/jump $assigns-in-stmt?:end/disp8 + } + # otherwise return false + b8/copy 0/imm32/false +$assigns-in-stmt?:end: + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +assigns-in-stmt-vars?: # stmt-var: (addr stmt-var), v: (addr var) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # var curr/ecx: (addr stmt-var) = stmt-var + 8b/-> *(ebp+8) 1/r32/ecx + { + # if (curr == 0) break + 81 7/subop/compare %ecx 0/imm32 + 74/jump-if-= break/disp8 + # eax = lookup(curr->value) + (lookup *ecx *(ecx+4)) # Stmt-var-value Stmt-var-value => eax + # if (eax == v && curr->is-deref? == false) return true + { + 39/compare *(ebp+0xc) 0/r32/eax + 75/jump-if-!= break/disp8 + 81 7/subop/compare *(ecx+0x10) 0/imm32/false # Stmt-var-is-deref + 75/jump-if-!= break/disp8 + b8/copy-to-eax 1/imm32/true + eb/jump $assigns-in-stmt-vars?:end/disp8 + } + # curr = lookup(curr->next) + (lookup *(ecx+8) *(ecx+0xc)) # Stmt-var-next Stmt-var-next => eax + 89/<- %ecx 0/r32/eax + # + eb/jump loop/disp8 + } +$assigns-in-stmt-vars?:end: + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# is there a var before 'v' with the same block-depth and register on the 'vars' stack? +# v is guaranteed to be within vars +# 'start' is provided as an optimization, a pointer within vars +# *start == v +same-register-spilled-before?: # v: (addr var), vars: (addr stack (handle var)), start: (addr var) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + 57/push-edi + # ecx = v + 8b/-> *(ebp+8) 1/r32/ecx + # var reg/edx: (addr array byte) = lookup(v->register) + (lookup *(ecx+0x18) *(ecx+0x1c)) # Var-register Var-register => eax + 89/<- %edx 0/r32/eax + # var depth/ebx: int = v->block-depth + 8b/-> *(ecx+0x10) 3/r32/ebx # Var-block-depth + # var min/ecx: (addr handle var) = vars->data + 8b/-> *(ebp+0xc) 1/r32/ecx + 81 0/subop/add %ecx 8/imm32 + # TODO: check that start >= min and start < &vars->data[top] + # TODO: check that *start == v + # var curr/esi: (addr handle var) = start + 8b/-> *(ebp+0x10) 6/r32/esi + # curr -= 8 + 81 5/subop/subtract %esi 8/imm32 + { +$same-register-spilled-before?:loop: + # if (curr < min) break + 39/compare %esi 1/r32/ecx + 0f 82/jump-if-addr< break/disp32 + # var x/eax: (addr var) = lookup(*curr) + (lookup *esi *(esi+4)) # => eax + # if (x->block-depth < depth) break + 39/compare *(eax+0x10) 3/r32/ebx # Var-block-depth + 0f 8c/jump-if-< break/disp32 + # if (x->register == 0) continue + 81 7/subop/compare *(eax+0x18) 0/imm32 # Var-register + 74/jump-if-= $same-register-spilled-before?:continue/disp8 + # if (x->register == reg) return true + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + (string-equal? %eax %edx) # => eax + 3d/compare-eax-and 0/imm32/false + b8/copy-to-eax 1/imm32/true + 75/jump-if-!= $same-register-spilled-before?:end/disp8 +$same-register-spilled-before?:continue: + # curr -= 8 + 81 5/subop/subtract %esi 8/imm32 + e9/jump loop/disp32 + } +$same-register-spilled-before?:false: + b8/copy-to-eax 0/imm32/false +$same-register-spilled-before?:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# clean up global state for 'vars' until some block depth (inclusive) +clean-up-blocks: # vars: (addr stack live-var), until-block-depth: int, fn: (addr function) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 56/push-esi + # esi = vars + 8b/-> *(ebp+8) 6/r32/esi + # ecx = until-block-depth + 8b/-> *(ebp+0xc) 1/r32/ecx + { +$clean-up-blocks:reclaim-loop: + # if (vars->top <= 0) break + 8b/-> *esi 0/r32/eax # Stack-top + 3d/compare-eax-and 0/imm32 + 0f 8e/jump-if-<= break/disp32 + # var v/eax: (addr var) = lookup(vars[vars->top-12]) + (lookup *(esi+eax-4) *(esi+eax)) # vars + 8 + vars->top - 12 => eax + # if (v->block-depth < until-block-depth) break + 39/compare *(eax+0x10) 1/r32/ecx # Var-block-depth + 0f 8c/jump-if-< break/disp32 + (pop %esi) # => eax + (pop %esi) # => eax + (pop %esi) # => eax + e9/jump loop/disp32 + } +$clean-up-blocks:end: + # . restore registers + 5e/pop-to-esi + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +reg-in-function-outputs?: # fn: (addr function), target: (addr array byte) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # var curr/ecx: (addr list var) = lookup(fn->outputs) + 8b/-> *(ebp+8) 0/r32/eax + (lookup *(eax+0x10) *(eax+0x14)) # Function-outputs Function-outputs => eax + 89/<- %ecx 0/r32/eax + # while curr != null + { + 81 7/subop/compare %ecx 0/imm32 + 74/jump-if-= break/disp8 + # var v/eax: (addr var) = lookup(curr->value) + (lookup *ecx *(ecx+4)) # List-value List-value => eax + # var reg/eax: (addr array byte) = lookup(v->register) + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + # if (reg == target) return true + (string-equal? %eax *(ebp+0xc)) # => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= $reg-in-function-outputs?:end/disp8 + # curr = curr->next + (lookup *(ecx+8) *(ecx+0xc)) # List-next List-next => eax + 89/<- %ecx 0/r32/eax + # + eb/jump loop/disp8 + } + # return false + b8/copy-to-eax 0/imm32 +$reg-in-function-outputs?:end: + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +emit-subx-var-def: # out: (addr buffered-file), stmt: (addr stmt) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + # eax = stmt + 8b/-> *(ebp+0xc) 0/r32/eax + # var v/ecx: (addr var) + (lookup *(eax+4) *(eax+8)) # Vardef-var Vardef-var => eax + 89/<- %ecx 0/r32/eax + # v->block-depth = *Curr-block-depth + 8b/-> *Curr-block-depth 0/r32/eax + 89/<- *(ecx+0x10) 0/r32/eax # Var-block-depth + # var n/edx: int = size-of(stmt->var) + (size-of %ecx) # => eax + 89/<- %edx 0/r32/eax + # *Curr-local-stack-offset -= n + 29/subtract-from *Curr-local-stack-offset 2/r32/edx + # v->offset = *Curr-local-stack-offset + 8b/-> *Curr-local-stack-offset 0/r32/eax + 89/<- *(ecx+0x14) 0/r32/eax # Var-offset + # if v is an array, do something special to initialize it + { + (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + (is-mu-array? %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= break/disp32 + # var array-size-without-size/edx: int = n-4 + 81 5/subop/subtract %edx 4/imm32 + # + (emit-array-data-initialization *(ebp+8) %edx) + e9/jump $emit-subx-var-def:end/disp32 + } + # another special-case for initializing streams + # a stream is an array with 2 extra pointers + { + (lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax + (is-mu-stream? %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= break/disp32 + # var array-size-without-size/edx: int = n-12 + 81 5/subop/subtract %edx 0xc/imm32 + (emit-array-data-initialization *(ebp+8) %edx) + # emit read and write pointers + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "68/push 0/imm32\n") + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "68/push 0/imm32\n") + # + eb/jump $emit-subx-var-def:end/disp8 + } + # while n > 0 + { + 81 7/subop/compare %edx 0/imm32 + 7e/jump-if-<= break/disp8 + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "68/push 0/imm32\n") + # n -= 4 + 81 5/subop/subtract %edx 4/imm32 + # + eb/jump loop/disp8 + } +$emit-subx-var-def:end: + # . restore registers + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +emit-array-data-initialization: # out: (addr buffered-file), n: int + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "(push-n-zero-bytes ") + (write-int32-hex-buffered *(ebp+8) *(ebp+0xc)) + (write-buffered *(ebp+8) ")\n") + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "68/push ") + (write-int32-hex-buffered *(ebp+8) *(ebp+0xc)) + (write-buffered *(ebp+8) "/imm32\n") +$emit-array-data-initialization:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +emit-subx-stmt: # out: (addr buffered-file), stmt: (addr stmt), primitives: (addr primitive), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + # - some special-case primitives that don't actually use the 'primitives' data structure + # var op/ecx: (addr array byte) = lookup(stmt->operation) + 8b/-> *(ebp+0xc) 1/r32/ecx + (lookup *(ecx+4) *(ecx+8)) # Stmt1-operation Stmt1-operation => eax + 89/<- %ecx 0/r32/eax + # copy byte (can be a primitive except we need to emit a second instruction) + { + # if (!string-equal?(stmt->operation, "copy-byte")) break + (string-equal? %ecx "copy-byte") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= break/disp32 + (translate-mu-copy-byte-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c)) + e9/jump $emit-subx-stmt:end/disp32 + } + # copy-byte-to can be a primitive; writes to memory don't need to clear surrounding bytes + # array size + { + # if (!string-equal?(stmt->operation, "length")) break + (string-equal? %ecx "length") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= break/disp32 + (translate-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c)) + e9/jump $emit-subx-stmt:end/disp32 + } + # index into array + { + # if (!string-equal?(stmt->operation, "index")) break + (string-equal? %ecx "index") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= break/disp32 + (translate-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c)) + e9/jump $emit-subx-stmt:end/disp32 + } + # compute-offset for index into array + { + # if (!string-equal?(stmt->operation, "compute-offset")) break + (string-equal? %ecx "compute-offset") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= break/disp32 + (translate-mu-compute-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c)) + e9/jump $emit-subx-stmt:end/disp32 + } + # get field from record + { + # if (!string-equal?(stmt->operation, "get")) break + (string-equal? %ecx "get") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= break/disp32 + (translate-mu-get-stmt *(ebp+8) *(ebp+0xc)) + e9/jump $emit-subx-stmt:end/disp32 + } + # allocate scalar + { + # if (!string-equal?(stmt->operation, "allocate")) break + (string-equal? %ecx "allocate") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= break/disp32 + (translate-mu-allocate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c)) + e9/jump $emit-subx-stmt:end/disp32 + } + # copy-object + { + # if (!string-equal?(stmt->operation, "copy-object")) break + (string-equal? %ecx "copy-object") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= break/disp32 + (translate-mu-copy-object-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c)) + e9/jump $emit-subx-stmt:end/disp32 + } + # clear-object + { + # if (!string-equal?(stmt->operation, "clear-object")) break + (string-equal? %ecx "clear-object") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= break/disp32 + (translate-mu-clear-object-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c)) + e9/jump $emit-subx-stmt:end/disp32 + } + # allocate array + { + # if (!string-equal?(stmt->operation, "populate")) break + (string-equal? %ecx "populate") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= break/disp32 + (translate-mu-populate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c)) + e9/jump $emit-subx-stmt:end/disp32 + } + # allocate stream + { + # if (!string-equal?(stmt->operation, "populate-stream")) break + (string-equal? %ecx "populate-stream") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= break/disp32 + (translate-mu-populate-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c)) + e9/jump $emit-subx-stmt:end/disp32 + } + # read from stream + { + # if (!string-equal?(stmt->operation, "read-from-stream")) break + (string-equal? %ecx "read-from-stream") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= break/disp32 + (translate-mu-read-from-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c)) + e9/jump $emit-subx-stmt:end/disp32 + } + # write to stream + { + # if (!string-equal?(stmt->operation, "write-to-stream")) break + (string-equal? %ecx "write-to-stream") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= break/disp32 + (translate-mu-write-to-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c)) + e9/jump $emit-subx-stmt:end/disp32 + } + # - optimizations + # if copy instruction has same register in source and destination, emit nothing + (is-redundant-copy? *(ebp+0xc)) # => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= $emit-subx-stmt:end/disp8 + # - if stmt matches a primitive, emit it + { +$emit-subx-stmt:check-for-primitive: + # var curr/eax: (addr primitive) + (find-matching-primitive *(ebp+0x10) *(ebp+0xc)) # primitives, stmt => eax + 3d/compare-eax-and 0/imm32 + 74/jump-if-= break/disp8 +$emit-subx-stmt:primitive: + (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr + e9/jump $emit-subx-stmt:end/disp32 + } + # - otherwise emit a call + # TODO: type-checking +$emit-subx-stmt:call: + (emit-call *(ebp+8) *(ebp+0xc)) +$emit-subx-stmt:end: + # . restore registers + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +is-redundant-copy?: # stmt: (addr stmt) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 56/push-esi + 57/push-edi + # esi = stmt + 8b/-> *(ebp+8) 6/r32/esi + # if stmt->operation != "copy" return false + (lookup *(esi+4) *(esi+8)) # Stmt1-operation Stmt1-operation => eax + (string-equal? %eax "copy") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $is-redundant-copy?:end/disp32 + # var output-reg/edi: (addr stmt-var) = stmt->outputs->value->register + (lookup *(esi+0x14) *(esi+0x18)) # Stmt1-outputs Stmt1-outputs => eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + # . if output-reg == null, return false + 3d/compare-eax-and 0/imm32 + 74/jump-if-= $is-redundant-copy?:end/disp8 + 89/<- %edi 0/r32/eax + # return (inout->value->register == output->value->register) + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + # . if inout->is-deref return false + 81 7/subop/compare *(eax+0x10) 0/imm32/false # Stmt-var-is-deref + { + 74/jump-if-= break/disp8 + b8/copy-to-eax 0/imm32/false + e9/jump $is-redundant-copy?:end/disp32 + } + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + # . if inout-reg == null, return false + 3d/compare-eax-and 0/imm32 + 74/jump-if-= $is-redundant-copy?:end/disp8 + (string-equal? %eax %edi) # => eax +$is-redundant-copy?:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +translate-mu-length-stmt: # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + # esi = stmt + 8b/-> *(ebp+0xc) 6/r32/esi + # var base/ebx: (addr var) = stmt->inouts[0]->value + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %ebx 0/r32/eax + # var elemsize/ecx: int = array-element-size(base) + (array-element-size %ebx *(ebp+0x10) *(ebp+0x14)) # => eax + 89/<- %ecx 0/r32/eax + # var outreg/edx: (addr array byte) = stmt->outputs[0]->value->register + (lookup *(esi+0x14) *(esi+0x18)) # Stmt1-outputs Stmt1-outputs => eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + 89/<- %edx 0/r32/eax + # if elemsize == 1 + { + 81 7/subop/compare %ecx 1/imm32 + 75/jump-if-!= break/disp8 +$translate-mu-length-stmt:size-1: + (emit-save-size-to *(ebp+8) %ebx %edx) + e9/jump $translate-mu-length-stmt:end/disp32 + } + # if elemsize is a power of 2 less than 256 + { + (power-of-2? %ecx *(ebp+0x10) *(ebp+0x14)) # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + 81 7/subop/compare %ecx 0xff/imm32 + 7f/jump-if-> break/disp8 +$translate-mu-length-stmt:size-power-of-2: + (emit-save-size-to *(ebp+8) %ebx %edx) + (emit-divide-by-shift-right *(ebp+8) %edx %ecx) + e9/jump $translate-mu-length-stmt:end/disp32 + } + # otherwise, the complex case + # . emit register spills + { +$translate-mu-length-stmt:complex: + (string-equal? %edx "eax") # => eax + 3d/compare-eax-and 0/imm32/false + 75/break-if-!= break/disp8 + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "50/push-eax\n") + } + { + (string-equal? %edx "ecx") # => eax + 3d/compare-eax-and 0/imm32/false + 75/break-if-!= break/disp8 + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "51/push-ecx\n") + } + { + (string-equal? %edx "edx") # => eax + 3d/compare-eax-and 0/imm32/false + 75/break-if-!= break/disp8 + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "52/push-edx\n") + } + # . + (emit-save-size-to *(ebp+8) %ebx "eax") + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "31/xor %edx 2/r32/edx\n") + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "b9/copy-to-ecx ") + (write-int32-hex-buffered *(ebp+8) %ecx) + (write-buffered *(ebp+8) "/imm32\n") + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "f7 7/subop/idiv-eax-edx-by %ecx\n") + { + (string-equal? %edx "eax") # => eax + 3d/compare-eax-and 0/imm32/false + 75/break-if-!= break/disp8 + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "89/<- %") + (write-buffered *(ebp+8) %edx) + (write-buffered *(ebp+8) " 0/r32/eax\n") + } + # . emit register restores + { + (string-equal? %edx "edx") # => eax + 3d/compare-eax-and 0/imm32/false + 75/break-if-!= break/disp8 + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "5a/pop-to-edx\n") + } + { + (string-equal? %edx "ecx") # => eax + 3d/compare-eax-and 0/imm32/false + 75/break-if-!= break/disp8 + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "59/pop-to-ecx\n") + } + { + (string-equal? %edx "eax") # => eax + 3d/compare-eax-and 0/imm32/false + 75/break-if-!= break/disp8 + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "58/pop-to-eax\n") + } +$translate-mu-length-stmt:end: + # . restore registers + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +array-element-size: # arr: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # + (array-element-type-id *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax + (size-of-type-id-as-array-element %eax) # => eax +$array-element-size:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +array-element-type-id: # v: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: type-id + # precondition: n is positive + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # + 8b/-> *(ebp+8) 0/r32/eax + # var t/eax: (addr type-tree) + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + # if t == 0 abort + 3d/compare-eax-with 0/imm32 + 0f 84/jump-if-== $array-element-type-id:error0/disp32 + # if t->is-atom? abort + 81 7/subop/compare *eax 0/imm32/false # Type-tree-is-atom + 0f 85/jump-if-!= $array-element-type-id:error1/disp32 + # if (t->left == addr) t = t->right + { + 50/push-eax + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 2) # addr => eax + 3d/compare-eax-with 0/imm32/false + 58/pop-to-eax + 74/jump-if-= break/disp8 +$array-element-type-id:skip-addr: + (lookup *(eax+0xc) *(eax+0x10)) # Type-tree-right Type-tree-right => eax + } + # if t == 0 abort + 3d/compare-eax-with 0/imm32 + 0f 84/jump-if-= $array-element-type-id:error2/disp32 + # if t->is-atom? abort + 81 7/subop/compare *eax 0/imm32/false # Type-tree-is-atom + 0f 85/jump-if-!= $array-element-type-id:error2/disp32 + # if t->left != array abort + { + 50/push-eax + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 3) # array => eax + 3d/compare-eax-with 0/imm32/false + 58/pop-to-eax +$array-element-type-id:no-array: + 0f 84/jump-if-= $array-element-type-id:error2/disp32 + } +$array-element-type-id:skip-array: + # t = t->right + (lookup *(eax+0xc) *(eax+0x10)) # Type-tree-right Type-tree-right => eax + # if t == 0 abort + 3d/compare-eax-with 0/imm32 + 0f 84/jump-if-= $array-element-type-id:error2/disp32 + # if t->is-atom? abort + 81 7/subop/compare *eax 0/imm32/false # Type-tree-is-atom + 0f 85/jump-if-!= $array-element-type-id:error2/disp32 + # t = t->left + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + # if (!t->is-atom?) t = t->left # TODO: assumes array element size can be determined from just first word of array element type + # if (t->is-atom == false) t = lookup(t->left) + { + 81 7/subop/compare *eax 0/imm32/false # Type-tree-is-atom + 75/jump-if-!= break/disp8 + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } + # return t->value + 8b/-> *(eax+4) 0/r32/eax # Type-tree-value +$array-element-type-id:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$array-element-type-id:error0: + (write-buffered *(ebp+0xc) "array-element-type-id: var '") + 50/push-eax + 8b/-> *(ebp+8) 0/r32/eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0xc) %eax) + 58/pop-to-eax + (write-buffered *(ebp+0xc) "' has no type\n") + (flush *(ebp+0xc)) + (stop *(ebp+0x10) 1) + # never gets here + +$array-element-type-id:error1: + (write-buffered *(ebp+0xc) "array-element-type-id: var '") + 50/push-eax + 8b/-> *(ebp+8) 0/r32/eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0xc) %eax) + 58/pop-to-eax + (write-buffered *(ebp+0xc) "' has atomic type ") + (write-int32-hex-buffered *(ebp+0xc) *(eax+4)) # Type-tree-value + (write-buffered *(ebp+0xc) Newline) + (flush *(ebp+0xc)) + (stop *(ebp+0x10) 1) + # never gets here + +$array-element-type-id:error2: + (write-buffered *(ebp+0xc) "array-element-type-id: var '") + 50/push-eax + 8b/-> *(ebp+8) 0/r32/eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0xc) %eax) + 58/pop-to-eax + (write-buffered *(ebp+0xc) "' has non-array type\n") + (flush *(ebp+0xc)) + (stop *(ebp+0x10) 1) + # never gets here + +size-of-type-id-as-array-element: # t: type-id -> result/eax: int + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # eax = t + 8b/-> *(ebp+8) 0/r32/eax + # if t is 'byte', size is 1 + 3d/compare-eax-and 8/imm32/byte + { + 75/jump-if-!= break/disp8 + b8/copy-to-eax 1/imm32 + eb/jump $size-of-type-id-as-array-element:end/disp8 + } + # otherwise proceed as usual + (size-of-type-id %eax) # => eax +$size-of-type-id-as-array-element:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +emit-save-size-to: # out: (addr buffered-file), base: (addr var), outreg: (addr array byte) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 53/push-ebx + # ebx = base + 8b/-> *(ebp+0xc) 3/r32/ebx + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "8b/-> *") + # if base is an (addr array ...) in a register + { + 81 7/subop/compare *(ebx+0x18)) 0/imm32 # Var-register + 74/jump-if-= break/disp8 +$emit-save-size-to:emit-base-from-register: + (lookup *(ebx+0x18) *(ebx+0x1c)) # Var-register Var-register => eax + (write-buffered *(ebp+8) %eax) + eb/jump $emit-save-size-to:emit-output/disp8 + } + # otherwise if base is an (array ...) on the stack + { + 81 7/subop/compare *(ebx+0x14)) 0/imm32 # Var-offset + 74/jump-if-= break/disp8 +$emit-save-size-to:emit-base-from-stack: + (write-buffered *(ebp+8) "(ebp+") + (write-int32-hex-buffered *(ebp+8) *(ebx+0x14)) # Var-offset + (write-buffered *(ebp+8) ")") + } +$emit-save-size-to:emit-output: + (write-buffered *(ebp+8) " ") + (get Mu-registers *(ebp+0x10) 0xc "Mu-registers") # => eax + (write-int32-hex-buffered *(ebp+8) *eax) + (write-buffered *(ebp+8) "/r32\n") +$emit-save-size-to:end: + # . restore registers + 5b/pop-to-ebx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +emit-divide-by-shift-right: # out: (addr buffered-file), reg: (addr array byte), size: int + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + # + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "c1/shift 5/subop/>> %") + (write-buffered *(ebp+8) *(ebp+0xc)) + (write-buffered *(ebp+8) Space) + (num-shift-rights *(ebp+0x10)) # => eax + (write-int32-hex-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) "/imm8\n") +$emit-divide-by-shift-right:end: + # . restore registers + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +translate-mu-copy-byte-stmt: # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 56/push-esi + # esi = stmt + 8b/-> *(ebp+0xc) 6/r32/esi + # + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "8a/byte->") + # emit stmt->inouts[0] + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (emit-subx-var-as-rm32 *(ebp+8) %eax) + # emit /r32 for stmt->outputs[0]->register + (lookup *(esi+0x14) *(esi+0x18)) # Stmt1-outputs Stmt1-outputs => eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + (maybe-get Mu-registers %eax 0xc) # => eax: (addr register-index) + (write-buffered *(ebp+8) Space) + (write-int32-hex-buffered *(ebp+8) *eax) + (write-buffered *(ebp+8) "/r32\n") + # clear rest of register + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "81 4/subop/and %") + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *(esi+0x14) *(esi+0x18)) # Stmt1-outputs Stmt1-outputs => eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + (write-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) " 0xff/imm32\n") +$translate-mu-copy-byte-stmt:end: + # . restore registers + 5e/pop-to-esi + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# a little different from other translate- functions; notice the extra 'fn' argument +translate-mu-index-stmt: # out: (addr buffered-file), stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 53/push-ebx + # ebx = stmt + 8b/-> *(ebp+0xc) 3/r32/ebx + # var base/ebx: (addr var) = stmt->inouts[0] + (lookup *(ebx+0xc) *(ebx+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %ebx 0/r32/eax + # emit bounds-check + (emit-mu-index-bounds-check *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18)) + # if (var->register) do one thing + { + 81 7/subop/compare *(ebx+0x18) 0/imm32 # Var-register + 74/jump-if-= break/disp8 + # TODO: ensure there's no dereference + (translate-mu-index-stmt-with-array-in-register *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18)) + eb/jump $translate-mu-index-stmt:end/disp8 + } + # if (var->offset) do a different thing + { + 81 7/subop/compare *(ebx+0x14) 0/imm32 # Var-offset + 74/jump-if-= break/disp8 + # TODO: ensure there's no dereference + (translate-mu-index-stmt-with-array-on-stack *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18)) + eb/jump $translate-mu-index-stmt:end/disp8 + } +$translate-mu-index-stmt:end: + # . restore registers + 5b/pop-to-ebx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$translate-mu-index-stmt:error1: + (write-buffered *(ebp+0x14) "couldn't translate an index instruction. second (index) input must either lie in a register or be a literal\n") + (flush *(ebp+0x14)) + (stop *(ebp+0x18) 1) + # never gets here + +$translate-mu-index-stmt:error2: + (write-buffered *(ebp+0x14) "couldn't translate an index instruction. second (index) input when in a register must be an int or offset\n") + (flush *(ebp+0x14)) + (stop *(ebp+0x18) 1) + # never gets here + +emit-mu-index-bounds-check: # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + # ecx = stmt + 8b/-> *(ebp+0xc) 1/r32/ecx + # + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "(__check-mu-array-bounds ") +$emit-mu-index-bounds-check:compute-base: + # var base/ebx: (addr var) = inouts[0] + (lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %ebx 0/r32/eax +$emit-mu-index-bounds-check:emit-index: + # var index/edx: (addr var) = inouts[1] + (lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %edx 0/r32/eax + # if index->register, print its code + 81 7/subop/compare *(edx+0x18) 0/imm32 # Var-register + { + 0f 84/jump-if-= break/disp32 +$emit-mu-index-bounds-check:emit-register-index: + (write-buffered *(ebp+8) "%") + (lookup *(edx+0x18) *(edx+0x1c)) # Var-register Var-register => eax + (write-buffered *(ebp+8) %eax) + eb/jump $emit-mu-index-bounds-check:index-done/disp8 + } + # otherwise if index is a literal, print it +$emit-mu-index-bounds-check:emit-literal-index: + (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + (is-simple-mu-type? %eax 0) # => eax + 3d/compare-eax-and 0/imm32/false + { + 0f 84/jump-if-= break/disp32 + (lookup *edx *(edx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+8) %eax) + } +$emit-mu-index-bounds-check:index-done: + (write-buffered *(ebp+8) " ") +$emit-mu-index-bounds-check:emit-element-size: + # if index is a literal or int, print size of array element + { + { + (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + (is-simple-mu-type? %eax 0) # literal => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 + (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + (is-simple-mu-type? %eax 1) # int => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 + eb/jump $emit-mu-index-bounds-check:emit-element-size-offset/disp8 + } +$emit-mu-index-bounds-check:emit-int-register-index: + (array-element-size %ebx *(ebp+0x14) *(ebp+0x18)) # => eax + (write-int32-hex-buffered *(ebp+8) %eax) + e9/jump $emit-mu-index-bounds-check:emit-base/disp32 + } +$emit-mu-index-bounds-check:emit-element-size-offset: + # if index has type (offset ...), print "1" + (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + 81 7/subop/compare *eax 0/imm32/false # Type-tree-is-atom + { + 75/jump-if-!= break/disp8 + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 7) # => eax + 3d/compare-eax-and 0/imm32/false + { + 0f 84/jump-if-= break/disp32 +$emit-mu-index-bounds-check:emit-offset-register-index: + (write-buffered *(ebp+8) "1") + } + } +$emit-mu-index-bounds-check:emit-base: + # if base is in a register, print " *" base->register + 81 7/subop/compare *(ebx+0x18) 0/imm32 # Var-register + { + 74/jump-if-= break/disp8 + (write-buffered *(ebp+8) " *") + (lookup *(ebx+0x18) *(ebx+0x1c)) # Var-register Var-register => eax + (write-buffered *(ebp+8) %eax) + e9/jump $emit-mu-index-bounds-check:emit-function-name/disp32 + } + # otherwise print " *(ebp+" base->offset ")" + (write-buffered *(ebp+8) " *(ebp+") + (write-int32-hex-buffered *(ebp+8) *(ebx+0x14)) # Var-offset + (write-buffered *(ebp+8) ")") +$emit-mu-index-bounds-check:emit-function-name: + # " \"" function-name "\"" + (write-buffered *(ebp+8) " \"") + 8b/-> *(ebp+0x10) 1/r32/ecx + (lookup *ecx *(ecx+4)) # Function-name Function-name => eax + (write-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) "\"") +$emit-mu-index-bounds-check:emit-array-name: + # " \"" base->name "\"" + (write-buffered *(ebp+8) " \"") + (lookup *ebx *(ebx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) "\")\n") +$emit-mu-index-bounds-check:end: + # . restore registers + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +translate-mu-index-stmt-with-array-in-register: # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + # + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "8d/copy-address *(") + # TODO: ensure inouts[0] is in a register and not dereferenced +$translate-mu-index-stmt-with-array-in-register:emit-base: + # ecx = stmt + 8b/-> *(ebp+0xc) 1/r32/ecx + # var base/ebx: (addr var) = inouts[0] + (lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %ebx 0/r32/eax + # print base->register " + " + (lookup *(ebx+0x18) *(ebx+0x1c)) # Var-register Var-register => eax + (write-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) " + ") + # var index/edx: (addr var) = inouts[1] + (lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %edx 0/r32/eax + # if index->register + 81 7/subop/compare *(edx+0x18) 0/imm32 # Var-register + { + 0f 84/jump-if-= break/disp32 +$translate-mu-index-stmt-with-array-in-register:emit-register-index: + # if index is an int + (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + (is-simple-mu-type? %eax 1) # int => eax + 3d/compare-eax-and 0/imm32/false + { + 0f 84/jump-if-= break/disp32 +$translate-mu-index-stmt-with-array-in-register:emit-int-register-index: + # print index->register "<<" log2(array-element-size(base)) " + 4) " + # . index->register "<<" + (lookup *(edx+0x18) *(edx+0x1c)) # Var-register Var-register => eax + (write-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) "<<") + # . log2(array-element-size(base->type)) + # we know size is a power of 2 + (array-element-size %ebx *(ebp+0x10) *(ebp+0x14)) # => eax + (num-shift-rights %eax) # => eax + (write-int32-hex-buffered *(ebp+8) %eax) + e9/jump $translate-mu-index-stmt-with-array-in-register:emit-register-index-done/disp32 + } + # if index->type is any other atom, abort + (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + 81 7/subop/compare *eax 0/imm32/false # Type-tree-is-atom + 0f 85/jump-if-!= $translate-mu-index-stmt:error2/disp32 + # if index has type (offset ...) + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 7) # => eax + 3d/compare-eax-and 0/imm32/false + { + 0f 84/jump-if-= break/disp32 + # print index->register +$translate-mu-index-stmt-with-array-in-register:emit-offset-register-index: + (lookup *(edx+0x18) *(edx+0x1c)) # Var-register Var-register => eax + (write-buffered *(ebp+8) %eax) + } +$translate-mu-index-stmt-with-array-in-register:emit-register-index-done: + (write-buffered *(ebp+8) " + 4) ") + e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32 + } + # otherwise if index is a literal + (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + (is-simple-mu-type? %eax 0) # => eax + 3d/compare-eax-and 0/imm32/false + { + 0f 84/jump-if-= break/disp32 +$translate-mu-index-stmt-with-array-in-register:emit-literal-index: + # var index-value/edx: int = parse-hex-int(index->name) + (lookup *edx *(edx+4)) # Var-name Var-name => eax + (parse-hex-int %eax) # => eax + 89/<- %edx 0/r32/eax + # offset = idx-value * array-element-size(base->type) + (array-element-size %ebx *(ebp+0x10) *(ebp+0x14)) # => eax + f7 4/subop/multiply-into-edx-eax %edx # clobbers edx + # offset += 4 for array size + 05/add-to-eax 4/imm32 + # TODO: check edx for overflow + # print offset + (write-int32-hex-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) ") ") + e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32 + } + # otherwise abort + e9/jump $translate-mu-index-stmt:error1/disp32 +$translate-mu-index-stmt-with-array-in-register:emit-output: + # outputs[0] "/r32" + 8b/-> *(ebp+0xc) 1/r32/ecx + (lookup *(ecx+0x14) *(ecx+0x18)) # Stmt1-outputs Stmt1-outputs => eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + (get Mu-registers %eax 0xc "Mu-registers") # => eax: (addr int) + (write-int32-hex-buffered *(ebp+8) *eax) + (write-buffered *(ebp+8) "/r32\n") +$translate-mu-index-stmt-with-array-in-register:end: + # . restore registers + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +translate-mu-index-stmt-with-array-on-stack: # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + # + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "8d/copy-address *(ebp + ") + # var curr/edx: (addr stmt-var) = lookup(stmt->inouts) + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *(eax+0xc) *(eax+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 89/<- %edx 0/r32/eax + # var base/ecx: (addr var) = lookup(curr->value) + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %ecx 0/r32/eax + # var curr2/eax: (addr stmt-var) = lookup(curr->next) + (lookup *(edx+8) *(edx+0xc)) # Stmt-var-next Stmt-var-next => eax + # var index/edx: (handle var) = curr2->value + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %edx 0/r32/eax + # if index->register + 81 7/subop/compare *(edx+0x18) 0/imm32 # Var-register + { + 0f 84/jump-if-= break/disp32 +$translate-mu-index-stmt-with-array-on-stack:emit-register-index: + # if index is an int + (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + (is-simple-mu-type? %eax 1) # int => eax + 3d/compare-eax-and 0/imm32/false + { + 0f 84/jump-if-= break/disp32 +$translate-mu-index-stmt-with-array-on-stack:emit-int-register-index: + # print index->register "<<" log2(array-element-size(base)) " + " base->offset+4 + # . inouts[1]->register "<<" + (lookup *(edx+0x18) *(edx+0x1c)) # Var-register Var-register => eax + (write-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) "<<") + # . log2(array-element-size(base)) + # TODO: ensure size is a power of 2 + (array-element-size %ecx *(ebp+0x10) *(ebp+0x14)) # => eax + (num-shift-rights %eax) # => eax + (write-int32-hex-buffered *(ebp+8) %eax) + # + (write-buffered *(ebp+8) " + ") + # + 8b/-> *(ecx+0x14) 0/r32/eax # Var-offset + 05/add-to-eax 4/imm32 # for array length + (write-int32-hex-buffered *(ebp+8) %eax) + e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done/disp32 + } + # if index->type is any other atom, abort + (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + 81 7/subop/compare *eax 0/imm32/false # Type-tree-is-atom + 0f 85/jump-if-!= $translate-mu-index-stmt:error2/disp32 + # if index has type (offset ...) + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 7) # => eax + 3d/compare-eax-and 0/imm32/false + { + 0f 84/jump-if-= break/disp32 + # print index->register +$translate-mu-index-stmt-with-array-on-stack:emit-offset-register-index: + (lookup *(edx+0x18) *(edx+0x1c)) # Var-register Var-register => eax + (write-buffered *(ebp+8) %eax) + } +$translate-mu-index-stmt-with-array-on-stack:emit-register-index-done: + (write-buffered *(ebp+8) ") ") + e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32 + } + # otherwise if index is a literal + (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + (is-simple-mu-type? %eax 0) # => eax + 3d/compare-eax-and 0/imm32/false + { + 0f 84/jump-if-= break/disp32 +$translate-mu-index-stmt-with-array-on-stack:emit-literal-index: + # var idx-value/edx: int = parse-hex-int(index->name) + (lookup *edx *(edx+4)) # Var-name Var-name => eax + (parse-hex-int %eax) # Var-name => eax + 89/<- %edx 0/r32/eax + # offset = idx-value * array-element-size(base) + (array-element-size %ecx *(ebp+0x10) *(ebp+0x14)) # => eax + f7 4/subop/multiply-into-edx-eax %edx # clobbers edx + # offset += base->offset + 03/add *(ecx+0x14) 0/r32/eax # Var-offset + # offset += 4 for array size + 05/add-to-eax 4/imm32 + # TODO: check edx for overflow + # print offset + (write-int32-hex-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) ") ") + e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32 + } + # otherwise abort + e9/jump $translate-mu-index-stmt:error1/disp32 +$translate-mu-index-stmt-with-array-on-stack:emit-output: + # outputs[0] "/r32" + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *(eax+0x14) *(eax+0x18)) # Stmt1-outputs Stmt1-outputs => eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + (get Mu-registers %eax 0xc "Mu-registers") # => eax: (addr int) + (write-int32-hex-buffered *(ebp+8) *eax) + (write-buffered *(ebp+8) "/r32\n") +$translate-mu-index-stmt-with-array-on-stack:end: + # . restore registers + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +translate-mu-compute-index-stmt: # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + # + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "69/multiply") + # ecx = stmt + 8b/-> *(ebp+0xc) 1/r32/ecx + # var first-inout/ebx: (addr stmt-var) = stmt->inouts[0] + (lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 89/<- %ebx 0/r32/eax +$translate-mu-compute-index-stmt:emit-index: + (lookup *(ebx+8) *(ebx+0xc)) # Stmt-var-next Stmt-var-next => eax + (emit-subx-var-as-rm32 *(ebp+8) %eax) + (write-buffered *(ebp+8) Space) +$translate-mu-compute-index-stmt:emit-elem-size: + # var base/ebx: (addr var) + (lookup *ebx *(ebx+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %ebx 0/r32/eax + # print array-element-size(base) + (array-element-size %ebx *(ebp+0x10) *(ebp+0x14)) # => eax + (write-int32-hex-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) "/imm32 ") +$translate-mu-compute-index-stmt:emit-output: + # outputs[0] "/r32" + (lookup *(ecx+0x14) *(ecx+0x18)) # Stmt1-outputs Stmt1-outputs => eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + (get Mu-registers %eax 0xc "Mu-registers") # => eax: (addr int) + (write-int32-hex-buffered *(ebp+8) *eax) + (write-buffered *(ebp+8) "/r32\n") +$translate-mu-compute-index-stmt:end: + # . restore registers + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +translate-mu-get-stmt: # out: (addr buffered-file), stmt: (addr stmt) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + # + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "8d/copy-address ") + # ecx = stmt + 8b/-> *(ebp+0xc) 1/r32/ecx + # var offset/edx: int = get offset of stmt + (mu-get-offset %ecx) # => eax + 89/<- %edx 0/r32/eax + # var base/eax: (addr var) = stmt->inouts->value + (lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + # if base is in a register + 81 7/subop/compare *(eax+0x18) 0/imm32 # Var-register + { + 0f 84/jump-if-= break/disp32 +$translate-mu-get-stmt:emit-register-input: + # emit "*(" base->register " + " offset ") " + (write-buffered *(ebp+8) "*(") + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + (write-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) " + ") + (write-int32-hex-buffered *(ebp+8) %edx) + (write-buffered *(ebp+8) ") ") + e9/jump $translate-mu-get-stmt:emit-output/disp32 + } + # otherwise base is on the stack + { +$translate-mu-get-stmt:emit-stack-input: + # emit "*(ebp + " inouts[0]->stack-offset + offset ") " + (write-buffered *(ebp+8) "*(ebp+") + 03/add *(eax+0x14) 2/r32/edx # Var-offset + (write-int32-hex-buffered *(ebp+8) %edx) + (write-buffered *(ebp+8) ") ") + eb/jump $translate-mu-get-stmt:emit-output/disp8 + } +$translate-mu-get-stmt:emit-output: + # var output/eax: (addr var) = stmt->outputs->value + (lookup *(ecx+0x14) *(ecx+0x18)) # Stmt1-outputs Stmt1-outputs => eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + # emit offset->register "/r32" + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax + (get Mu-registers %eax 0xc "Mu-registers") # => eax: (addr int) + (write-int32-hex-buffered *(ebp+8) *eax) + (write-buffered *(ebp+8) "/r32\n") +$translate-mu-get-stmt:end: + # . restore registers + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +translate-mu-copy-object-stmt: # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + # + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "(copy-bytes") + # eax = stmt + 8b/-> *(ebp+0xc) 0/r32/eax + # var first-inout/eax: (addr stmt-var) = stmt->inouts[0] + (lookup *(eax+0xc) *(eax+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (emit-subx-call-operand *(ebp+8) %eax) + # var second-inout/eax: (addr stmt-var) = stmt->inouts[1] + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax + (emit-subx-call-operand *(ebp+8) %eax) + # emit size of inouts + (write-buffered *(ebp+8) Space) + (addr-payload-size %eax *(ebp+0x10) *(ebp+0x14)) # => eax + (write-int32-hex-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) ")\n") +$translate-mu-copy-object-stmt:end: + # . restore registers + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +translate-mu-clear-object-stmt: # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + # + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "(zero-out") + # eax = stmt + 8b/-> *(ebp+0xc) 0/r32/eax + # var dest/eax: (addr stmt-var) = stmt->inouts[0] + (lookup *(eax+0xc) *(eax+0x10)) # Stmt1-inouts Stmt1-inouts => eax + # + (emit-subx-call-operand *(ebp+8) %eax) + (write-buffered *(ebp+8) Space) + (addr-payload-size %eax *(ebp+0x10) *(ebp+0x14)) # => eax + (write-int32-hex-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) ")\n") +$translate-mu-clear-object-stmt:end: + # . restore registers + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +translate-mu-allocate-stmt: # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 56/push-esi + 57/push-edi + # esi = stmt + 8b/-> *(ebp+0xc) 6/r32/esi + # var target/edi: (addr stmt-var) = stmt->inouts[0] + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 89/<- %edi 0/r32/eax + # + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "(allocate Heap ") + (addr-handle-payload-size %edi *(ebp+0x10) *(ebp+0x14)) # => eax + (write-int32-hex-buffered *(ebp+8) %eax) + (emit-subx-call-operand *(ebp+8) %edi) + (write-buffered *(ebp+8) ")\n") +$translate-mu-allocate-stmt:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +addr-handle-payload-size: # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # var t/eax: (addr type-tree) = s->value->type + 8b/-> *(ebp+8) 0/r32/eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + # TODO: check eax != 0 + # TODO: check !t->is-atom? + # TODO: check t->left == addr + # t = t->right +$addr-handle-payload-size:skip-addr: + (lookup *(eax+0xc) *(eax+0x10)) # Type-tree-right Type-tree-right => eax + # TODO: check eax != 0 + # TODO: check !t->is-atom? + # TODO: check t->left == handle + # t = t->right +$addr-handle-payload-size:skip-handle: + (lookup *(eax+0xc) *(eax+0x10)) # Type-tree-right Type-tree-right => eax + # TODO: check eax != 0 + # if !t->is-atom? t = t->left + 81 7/subop/compare *eax 0/imm32/false + { + 75/jump-if-!= break/disp8 + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } + # TODO: check t->is-atom? + # return size(t->value) + (size-of-type-id *(eax+4)) # Type-tree-value => eax +$addr-handle-payload-size:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +addr-payload-size: # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # var t/eax: (addr type-tree) = s->value->type + 8b/-> *(ebp+8) 0/r32/eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + # TODO: check eax != 0 + # TODO: check !t->is-atom? + # TODO: check t->left == addr + # t = t->right +$addr-payload-size:skip-addr: + (lookup *(eax+0xc) *(eax+0x10)) # Type-tree-right Type-tree-right => eax + # TODO: check eax != 0 + # if !t->is-atom? t = t->left + 81 7/subop/compare *eax 0/imm32/false + { + 75/jump-if-!= break/disp8 + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } + # TODO: check t->is-atom? + # return size(t->value) + (size-of-type-id *(eax+4)) # Type-tree-value => eax +$addr-payload-size:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +translate-mu-populate-stmt: # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 56/push-esi + 57/push-edi + # esi = stmt + 8b/-> *(ebp+0xc) 6/r32/esi + # var target/edi: (addr stmt-var) = stmt->inouts[0] + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 89/<- %edi 0/r32/eax + # var len/ecx: (addr stmt-var) = stmt->inouts[1] + (lookup *(edi+8) *(edi+0xc)) # Stmt-var-next Stmt-var-next => eax + 89/<- %ecx 0/r32/eax + # + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "(allocate-array2 Heap ") + (addr-handle-array-payload-size %edi *(ebp+0x10) *(ebp+0x14)) # => eax + (write-int32-hex-buffered *(ebp+8) %eax) + (emit-subx-call-operand *(ebp+8) %ecx) + (emit-subx-call-operand *(ebp+8) %edi) + (write-buffered *(ebp+8) ")\n") +$translate-mu-populate-stmt:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +translate-mu-populate-stream-stmt: # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 56/push-esi + 57/push-edi + # esi = stmt + 8b/-> *(ebp+0xc) 6/r32/esi + # var target/edi: (addr stmt-var) = stmt->inouts[0] + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 89/<- %edi 0/r32/eax + # var len/ecx: (addr stmt-var) = stmt->inouts[1] + (lookup *(edi+8) *(edi+0xc)) # Stmt-var-next Stmt-var-next => eax + 89/<- %ecx 0/r32/eax + # + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "(new-stream Heap ") + (addr-handle-stream-payload-size %edi *(ebp+0x10) *(ebp+0x14)) # => eax + (write-int32-hex-buffered *(ebp+8) %eax) + (emit-subx-call-operand *(ebp+8) %ecx) + (emit-subx-call-operand *(ebp+8) %edi) + (write-buffered *(ebp+8) ")\n") +$translate-mu-populate-stream-stmt:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +translate-mu-read-from-stream-stmt: # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 56/push-esi + 57/push-edi + # esi = stmt + 8b/-> *(ebp+0xc) 6/r32/esi + # var stream/ecx: (addr stmt-var) = stmt->inouts[0] + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 89/<- %ecx 0/r32/eax + # var target/edi: (addr stmt-var) = stmt->inouts[1] + (lookup *(ecx+8) *(ecx+0xc)) # Stmt-var-next Stmt-var-next => eax + 89/<- %edi 0/r32/eax + # + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "(read-from-stream") + (emit-subx-call-operand *(ebp+8) %ecx) + (emit-subx-call-operand *(ebp+8) %edi) + (write-buffered *(ebp+8) Space) + (addr-payload-size %edi *(ebp+0x10) *(ebp+0x14)) # => eax + (write-int32-hex-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) ")\n") +$translate-mu-read-from-stream-stmt:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +translate-mu-write-to-stream-stmt: # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 56/push-esi + 57/push-edi + # esi = stmt + 8b/-> *(ebp+0xc) 6/r32/esi + # var stream/ecx: (addr stmt-var) = stmt->inouts[0] + (lookup *(esi+0xc) *(esi+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 89/<- %ecx 0/r32/eax + # var target/edi: (addr stmt-var) = stmt->inouts[1] + (lookup *(ecx+8) *(ecx+0xc)) # Stmt-var-next Stmt-var-next => eax + 89/<- %edi 0/r32/eax + # + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "(write-to-stream") + (emit-subx-call-operand *(ebp+8) %ecx) + (flush *(ebp+8)) + (emit-subx-call-operand *(ebp+8) %edi) + (flush *(ebp+8)) + (write-buffered *(ebp+8) Space) + (flush *(ebp+8)) + (addr-payload-size %edi *(ebp+0x10) *(ebp+0x14)) # => eax + (write-int32-hex-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) ")\n") +$translate-mu-write-to-stream-stmt:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +addr-handle-array-payload-size: # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # var t/eax: (addr type-tree) = s->value->type + 8b/-> *(ebp+8) 0/r32/eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + # TODO: check eax != 0 + # TODO: check !t->is-atom? + # TODO: check t->left == addr + # t = t->right +$addr-handle-array-payload-size:skip-addr: + (lookup *(eax+0xc) *(eax+0x10)) # Type-tree-right Type-tree-right => eax + # TODO: check eax != 0 + # TODO: check !t->is-atom? + # TODO: check t->left == handle + # t = t->right +$addr-handle-array-payload-size:skip-handle: + (lookup *(eax+0xc) *(eax+0x10)) # Type-tree-right Type-tree-right => eax + # TODO: check eax != 0 + # TODO: check !t->is-atom? + # TODO: check t->left == array + # t = t->right +$addr-handle-array-payload-size:skip-array: + (lookup *(eax+0xc) *(eax+0x10)) # Type-tree-right Type-tree-right => eax + # TODO: check eax != 0 + # if !t->is-atom? t = t->left + 81 7/subop/compare *eax 0/imm32/false + { + 75/jump-if-!= break/disp8 + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } +$addr-handle-array-payload-size:compute-size: + # TODO: check t->is-atom? + # return size(t->value) + (size-of-type-id-as-array-element *(eax+4)) # Type-tree-value => eax +$addr-handle-array-payload-size:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +addr-handle-stream-payload-size: # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # var t/eax: (addr type-tree) = s->value->type + 8b/-> *(ebp+8) 0/r32/eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax + # TODO: check eax != 0 + # TODO: check !t->is-atom? + # TODO: check t->left == addr + # t = t->right +$addr-handle-stream-payload-size:skip-addr: + (lookup *(eax+0xc) *(eax+0x10)) # Type-tree-right Type-tree-right => eax + # TODO: check eax != 0 + # TODO: check !t->is-atom? + # TODO: check t->left == handle + # t = t->right +$addr-handle-stream-payload-size:skip-handle: + (lookup *(eax+0xc) *(eax+0x10)) # Type-tree-right Type-tree-right => eax + # TODO: check eax != 0 + # TODO: check !t->is-atom? + # TODO: check t->left == stream + # t = t->right +$addr-handle-stream-payload-size:skip-stream: + (lookup *(eax+0xc) *(eax+0x10)) # Type-tree-right Type-tree-right => eax + # TODO: check eax != 0 + # if !t->is-atom? t = t->left + 81 7/subop/compare *eax 0/imm32/false + { + 75/jump-if-!= break/disp8 + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } +$addr-handle-stream-payload-size:compute-size: + # TODO: check t->is-atom? + # return size(t->value) + (size-of-type-id-as-array-element *(eax+4)) # Type-tree-value => eax +$addr-handle-stream-payload-size:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +power-of-2?: # n: int, err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: boolean + # precondition: n is positive + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # eax = n + 8b/-> *(ebp+8) 0/r32/eax + # if (n < 0) abort + 3d/compare-eax-with 0/imm32 + 0f 8c/jump-if-< $power-of-2?:abort/disp32 + # var tmp/eax: int = n-1 + 48/decrement-eax + # var tmp2/eax: int = n & tmp + 23/and-> *(ebp+8) 0/r32/eax + # return (tmp2 == 0) + 3d/compare-eax-and 0/imm32 + 0f 94/set-byte-if-= %al + 81 4/subop/and %eax 0xff/imm32 +$power-of-2?:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$power-of-2?:abort: + (write-buffered *(ebp+0xc) "power-of-2?: negative number\n") + (flush *(ebp+0xc)) + (stop *(ebp+0x10) 1) + # never gets here + +num-shift-rights: # n: int -> result/eax: int + # precondition: n is a positive power of 2 + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # var curr/ecx: int = n + 8b/-> *(ebp+8) 1/r32/ecx + # result = 0 + b8/copy-to-eax 0/imm32 + { + # if (curr <= 1) break + 81 7/subop/compare %ecx 1/imm32 + 7e/jump-if-<= break/disp8 + 40/increment-eax + c1/shift 5/subop/arithmetic-right %ecx 1/imm8 + eb/jump loop/disp8 + } +$num-shift-rights:end: + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +mu-get-offset: # stmt: (addr stmt) -> result/eax: int + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # var second-inout/eax: (addr stmt-var) = stmt->inouts->next + 8b/-> *(ebp+8) 0/r32/eax + (lookup *(eax+0xc) *(eax+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax + # var output-var/eax: (addr var) = second-inout->value + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax +#? (write-buffered Stderr "mu-get-offset: ") +#? (write-int32-hex-buffered Stderr %eax) +#? (write-buffered Stderr " name: ") +#? 50/push-eax +#? (lookup *eax *(eax+4)) # Var-name +#? (write-buffered Stderr %eax) +#? 58/pop-to-eax +#? (write-buffered Stderr Newline) +#? (flush Stderr) + # return output-var->stack-offset + 8b/-> *(eax+0x14) 0/r32/eax # Var-offset +#? (write-buffered Stderr "=> ") +#? (write-int32-hex-buffered Stderr %eax) +#? (write-buffered Stderr Newline) +#? (flush Stderr) +$emit-get-offset:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +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) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 56/push-esi + # esi = block + 8b/-> *(ebp+0xc) 6/r32/esi + # block->var->block-depth = *Curr-block-depth + (lookup *(esi+0xc) *(esi+0x10)) # Block-var Block-var => eax + 8b/-> *Curr-block-depth 1/r32/ecx + 89/<- *(eax+0x10) 1/r32/ecx # Var-block-depth + # var stmts/eax: (addr list stmt) = lookup(block->statements) + (lookup *(esi+4) *(esi+8)) # Block-stmts Block-stmts => eax + # + { +$emit-subx-block:check-empty: + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= break/disp32 + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "{\n") + # var v/ecx: (addr var) = lookup(block->var) + (lookup *(esi+0xc) *(esi+0x10)) # Block-var Block-var => eax + 89/<- %ecx 0/r32/eax + # + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) ":loop:\n") + ff 0/subop/increment *Curr-block-depth + (push *(ebp+0x10) *(esi+0xc)) # Block-var + (push *(ebp+0x10) *(esi+0x10)) # Block-var + (push *(ebp+0x10) 0) # false + # emit block->statements + (lookup *(esi+4) *(esi+8)) # Block-stmts Block-stmts => eax + (emit-subx-stmt-list *(ebp+8) %eax *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c)) + (pop *(ebp+0x10)) # => eax + (pop *(ebp+0x10)) # => eax + (pop *(ebp+0x10)) # => eax + ff 1/subop/decrement *Curr-block-depth + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "}\n") + (lookup *ecx *(ecx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) ":break:\n") + } +$emit-subx-block:end: + # . restore registers + 5e/pop-to-esi + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# Primitives supported +# See mu_instructions for a summary of this linked-list data structure. +# +# For each operation, put variants with hard-coded registers before flexible ones. +# +# Unfortunately, our restrictions on addresses require that various fields in +# primitives be handles, which complicates these definitions. +# - we need to insert dummy fields all over the place for fake alloc-ids +# - we can't use our syntax sugar of quoted literals for string fields +# +# Fake alloc-ids are needed because our type definitions up top require +# handles but it's clearer to statically allocate these long-lived objects. +# Fake alloc-ids are perfectly safe, but they can't be reclaimed. +# +# Every 'object' below starts with a fake alloc-id. It may also contain other +# fake alloc-ids for various handle fields. +# +# I think of objects starting with a fake alloc-id as having type 'payload'. +# It's not really intended to be created dynamically; for that use `allocate` +# as usual. +# +# Idea for a notation to simplify such definitions: +# _Primitive-increment-eax: # (payload primitive) +# 0x11/alloc-id:fake:payload +# 0x11 @(0x11 "increment") # name +# 0 0 # inouts +# 0x11 @(0x11/payload +# 0x11 @(0x11/payload # List-value +# 0 0 # Var-name +# 0x11 @(0x11 # Var-type +# 1/is-atom +# 1/value 0/unused # Type-tree-left +# 0 0 # Type-tree-right +# ) +# 1 # block-depth +# 0 # stack-offset +# 0x11 @(0x11 "eax") # Var-register +# ) +# 0 0) # List-next +# ... +# _Primitive-increment-ecx/imm32/next +# ... +# Awfully complex and non-obvious. But also clearly signals there's something +# to learn here, so may be worth trying. +# +# '@' is just an initial thought. Punctuation used so far in Mu: () * % # / " +# +# For now we'll continue to just use comments and manually ensure they stay up +# to date. +== data +Primitives: # (addr primitive) +# - increment/decrement +_Primitive-increment-eax: # (addr primitive) + # var/eax <- increment => 40/increment-eax + 0x11/imm32/alloc-id:fake + _string-increment/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-eax/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_40_increment_eax/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-increment-ecx/imm32/next +_Primitive-increment-ecx: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var/ecx <- increment => 41/increment-ecx + 0x11/imm32/alloc-id:fake + _string-increment/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-ecx/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_41_increment_ecx/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-increment-edx/imm32/next +_Primitive-increment-edx: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var/edx <- increment => 42/increment-edx + 0x11/imm32/alloc-id:fake + _string-increment/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-edx/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_42_increment_edx/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-increment-ebx/imm32/next +_Primitive-increment-ebx: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var/ebx <- increment => 43/increment-ebx + 0x11/imm32/alloc-id:fake + _string-increment/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-ebx/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_43_increment_ebx/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-increment-esi/imm32/next +_Primitive-increment-esi: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var/esi <- increment => 46/increment-esi + 0x11/imm32/alloc-id:fake + _string-increment/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-esi/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_46_increment_esi/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-increment-edi/imm32/next +_Primitive-increment-edi: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var/edi <- increment => 47/increment-edi + 0x11/imm32/alloc-id:fake + _string-increment/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-edi/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_47_increment_edi/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-decrement-eax/imm32/next +_Primitive-decrement-eax: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var/eax <- decrement => 48/decrement-eax + 0x11/imm32/alloc-id:fake + _string-decrement/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-eax/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_48_decrement_eax/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-decrement-ecx/imm32/next +_Primitive-decrement-ecx: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var/ecx <- decrement => 49/decrement-ecx + 0x11/imm32/alloc-id:fake + _string-decrement/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-ecx/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_49_decrement_ecx/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-decrement-edx/imm32/next +_Primitive-decrement-edx: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var/edx <- decrement => 4a/decrement-edx + 0x11/imm32/alloc-id:fake + _string-decrement/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-edx/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_4a_decrement_edx/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-decrement-ebx/imm32/next +_Primitive-decrement-ebx: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var/ebx <- decrement => 4b/decrement-ebx + 0x11/imm32/alloc-id:fake + _string-decrement/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-ebx/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_4b_decrement_ebx/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-decrement-esi/imm32/next +_Primitive-decrement-esi: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var/esi <- decrement => 4e/decrement-esi + 0x11/imm32/alloc-id:fake + _string-decrement/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-esi/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_4e_decrement_esi/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-decrement-edi/imm32/next +_Primitive-decrement-edi: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var/edi <- decrement => 4f/decrement-edi + 0x11/imm32/alloc-id:fake + _string-decrement/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-edi/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_4f_decrement_edi/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-increment-mem/imm32/next +_Primitive-increment-mem: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # increment var => ff 0/subop/increment *(ebp+__) + 0x11/imm32/alloc-id:fake + _string-increment/imm32/name + 0x11/imm32/alloc-id:fake + Single-int-var-in-mem/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_ff_subop_increment/imm32/subx-name + 1/imm32/rm32-is-first-inout + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-increment-reg/imm32/next +_Primitive-increment-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var/reg <- increment => ff 0/subop/increment %__ + 0x11/imm32/alloc-id:fake + _string-increment/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_ff_subop_increment/imm32/subx-name + 3/imm32/rm32-is-first-output + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-decrement-mem/imm32/next +_Primitive-decrement-mem: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # decrement var => ff 1/subop/decrement *(ebp+__) + 0x11/imm32/alloc-id:fake + _string-decrement/imm32/name + 0x11/imm32/alloc-id:fake + Single-int-var-in-mem/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_ff_subop_decrement/imm32/subx-name + 1/imm32/rm32-is-first-inout + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-decrement-reg/imm32/next +_Primitive-decrement-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var/reg <- decrement => ff 1/subop/decrement %__ + 0x11/imm32/alloc-id:fake + _string-decrement/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_ff_subop_decrement/imm32/subx-name + 3/imm32/rm32-is-first-output + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-add-to-eax/imm32/next +# - add +_Primitive-add-to-eax: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var/eax <- add lit => 05/add-to-eax lit/imm32 + 0x11/imm32/alloc-id:fake + _string-add/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-eax/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_05_add_to_eax/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 1/imm32/imm32-is-first-inout + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-add-reg-to-reg/imm32/next +_Primitive-add-reg-to-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32 + 0x11/imm32/alloc-id:fake + _string-add/imm32/name + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_01_add_to/imm32/subx-name + 3/imm32/rm32-is-first-output + 1/imm32/r32-is-first-inout + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-add-reg-to-mem/imm32/next +_Primitive-add-reg-to-mem: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # add-to var1 var2/reg => 01/add-to var1 var2/r32 + 0x11/imm32/alloc-id:fake + _string-add-to/imm32/name + 0x11/imm32/alloc-id:fake + Two-args-int-stack-int-reg/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_01_add_to/imm32/subx-name + 1/imm32/rm32-is-first-inout + 2/imm32/r32-is-second-inout + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-add-mem-to-reg/imm32/next +_Primitive-add-mem-to-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- add var2 => 03/add var2/rm32 var1/r32 + 0x11/imm32/alloc-id:fake + _string-add/imm32/name + 0x11/imm32/alloc-id:fake + Single-int-var-in-mem/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_03_add/imm32/subx-name + 1/imm32/rm32-is-first-inout + 3/imm32/r32-is-first-output + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-add-lit-to-reg/imm32/next +_Primitive-add-lit-to-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32 + 0x11/imm32/alloc-id:fake + _string-add/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_81_subop_add/imm32/subx-name + 3/imm32/rm32-is-first-output + 0/imm32/no-r32 + 1/imm32/imm32-is-first-inout + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-add-lit-to-mem/imm32/next +_Primitive-add-lit-to-mem: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32 + 0x11/imm32/alloc-id:fake + _string-add-to/imm32/name + 0x11/imm32/alloc-id:fake + Int-var-and-literal/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_81_subop_add/imm32/subx-name + 1/imm32/rm32-is-first-inout + 0/imm32/no-r32 + 2/imm32/imm32-is-second-inout + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-subtract-from-eax/imm32/next +# - subtract +_Primitive-subtract-from-eax: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32 + 0x11/imm32/alloc-id:fake + _string-subtract/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-eax/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_2d_subtract_from_eax/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 1/imm32/imm32-is-first-inout + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-subtract-reg-from-reg/imm32/next +_Primitive-subtract-reg-from-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32 + 0x11/imm32/alloc-id:fake + _string-subtract/imm32/name + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_29_subtract_from/imm32/subx-name + 3/imm32/rm32-is-first-output + 1/imm32/r32-is-first-inout + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-subtract-reg-from-mem/imm32/next +_Primitive-subtract-reg-from-mem: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32 + 0x11/imm32/alloc-id:fake + _string-subtract-from/imm32/name + 0x11/imm32/alloc-id:fake + Two-args-int-stack-int-reg/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_29_subtract_from/imm32/subx-name + 1/imm32/rm32-is-first-inout + 2/imm32/r32-is-second-inout + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-subtract-mem-from-reg/imm32/next +_Primitive-subtract-mem-from-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32 + 0x11/imm32/alloc-id:fake + _string-subtract/imm32/name + 0x11/imm32/alloc-id:fake + Single-int-var-in-mem/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_2b_subtract/imm32/subx-name + 1/imm32/rm32-is-first-inout + 3/imm32/r32-is-first-output + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-subtract-lit-from-reg/imm32/next +_Primitive-subtract-lit-from-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32 + 0x11/imm32/alloc-id:fake + _string-subtract/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_81_subop_subtract/imm32/subx-name + 3/imm32/rm32-is-first-output + 0/imm32/no-r32 + 1/imm32/imm32-is-first-inout + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-subtract-lit-from-mem/imm32/next +_Primitive-subtract-lit-from-mem: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32 + 0x11/imm32/alloc-id:fake + _string-subtract-from/imm32/name + 0x11/imm32/alloc-id:fake + Int-var-and-literal/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_81_subop_subtract/imm32/subx-name + 1/imm32/rm32-is-first-inout + 0/imm32/no-r32 + 2/imm32/imm32-is-second-inout + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-and-with-eax/imm32/next +# - and +_Primitive-and-with-eax: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var/eax <- and lit => 25/and-with-eax lit/imm32 + 0x11/imm32/alloc-id:fake + _string-and/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-eax/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_25_and_with_eax/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 1/imm32/imm32-is-first-inout + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-and-reg-with-reg/imm32/next +_Primitive-and-reg-with-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32 + 0x11/imm32/alloc-id:fake + _string-and/imm32/name + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_21_and_with/imm32/subx-name + 3/imm32/rm32-is-first-output + 1/imm32/r32-is-first-inout + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-and-reg-with-mem/imm32/next +_Primitive-and-reg-with-mem: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # and-with var1 var2/reg => 21/and-with var1 var2/r32 + 0x11/imm32/alloc-id:fake + _string-and-with/imm32/name + 0x11/imm32/alloc-id:fake + Two-args-int-stack-int-reg/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_21_and_with/imm32/subx-name + 1/imm32/rm32-is-first-inout + 2/imm32/r32-is-second-inout + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-and-mem-with-reg/imm32/next +_Primitive-and-mem-with-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- and var2 => 23/and var2/rm32 var1/r32 + 0x11/imm32/alloc-id:fake + _string-and/imm32/name + 0x11/imm32/alloc-id:fake + Single-int-var-in-mem/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_23_and/imm32/subx-name + 1/imm32/rm32-is-first-inout + 3/imm32/r32-is-first-output + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-and-lit-with-reg/imm32/next +_Primitive-and-lit-with-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32 + 0x11/imm32/alloc-id:fake + _string-and/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_81_subop_and/imm32/subx-name + 3/imm32/rm32-is-first-output + 0/imm32/no-r32 + 1/imm32/imm32-is-first-inout + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-and-lit-with-mem/imm32/next +_Primitive-and-lit-with-mem: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32 + 0x11/imm32/alloc-id:fake + _string-and-with/imm32/name + 0x11/imm32/alloc-id:fake + Int-var-and-literal/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_81_subop_and/imm32/subx-name + 1/imm32/rm32-is-first-inout + 0/imm32/no-r32 + 2/imm32/imm32-is-second-inout + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-or-with-eax/imm32/next +# - or +_Primitive-or-with-eax: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var/eax <- or lit => 0d/or-with-eax lit/imm32 + 0x11/imm32/alloc-id:fake + _string-or/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-eax/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_0d_or_with_eax/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 1/imm32/imm32-is-first-inout + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-or-reg-with-reg/imm32/next +_Primitive-or-reg-with-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32 + 0x11/imm32/alloc-id:fake + _string-or/imm32/name + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_09_or_with/imm32/subx-name + 3/imm32/rm32-is-first-output + 1/imm32/r32-is-first-inout + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-or-reg-with-mem/imm32/next +_Primitive-or-reg-with-mem: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # or-with var1 var2/reg => 09/or-with var1 var2/r32 + 0x11/imm32/alloc-id:fake + _string-or-with/imm32/name + 0x11/imm32/alloc-id:fake + Two-args-int-stack-int-reg/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_09_or_with/imm32/subx-name + 1/imm32/rm32-is-first-inout + 2/imm32/r32-is-second-inout + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-or-mem-with-reg/imm32/next +_Primitive-or-mem-with-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32 + 0x11/imm32/alloc-id:fake + _string-or/imm32/name + 0x11/imm32/alloc-id:fake + Single-int-var-in-mem/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_0b_or/imm32/subx-name + 1/imm32/rm32-is-first-inout + 3/imm32/r32-is-first-output + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-or-lit-with-reg/imm32/next +_Primitive-or-lit-with-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32 + 0x11/imm32/alloc-id:fake + _string-or/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_81_subop_or/imm32/subx-name + 3/imm32/rm32-is-first-output + 0/imm32/no-r32 + 1/imm32/imm32-is-first-inout + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-or-lit-with-mem/imm32/next +_Primitive-or-lit-with-mem: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32 + 0x11/imm32/alloc-id:fake + _string-or-with/imm32/name + 0x11/imm32/alloc-id:fake + Int-var-and-literal/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_81_subop_or/imm32/subx-name + 1/imm32/rm32-is-first-inout + 0/imm32/no-r32 + 2/imm32/imm32-is-second-inout + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-xor-with-eax/imm32/next +# - xor +_Primitive-xor-with-eax: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var/eax <- xor lit => 35/xor-with-eax lit/imm32 + 0x11/imm32/alloc-id:fake + _string-xor/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-eax/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_35_xor_with_eax/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 1/imm32/imm32-is-first-inout + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-xor-reg-with-reg/imm32/next +_Primitive-xor-reg-with-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32 + 0x11/imm32/alloc-id:fake + _string-xor/imm32/name + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_31_xor_with/imm32/subx-name + 3/imm32/rm32-is-first-output + 1/imm32/r32-is-first-inout + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-xor-reg-with-mem/imm32/next +_Primitive-xor-reg-with-mem: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # xor-with var1 var2/reg => 31/xor-with var1 var2/r32 + 0x11/imm32/alloc-id:fake + _string-xor-with/imm32/name + 0x11/imm32/alloc-id:fake + Two-args-int-stack-int-reg/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_31_xor_with/imm32/subx-name + 1/imm32/rm32-is-first-inout + 2/imm32/r32-is-second-inout + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-xor-mem-with-reg/imm32/next +_Primitive-xor-mem-with-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32 + 0x11/imm32/alloc-id:fake + _string-xor/imm32/name + 0x11/imm32/alloc-id:fake + Single-int-var-in-mem/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_33_xor/imm32/subx-name + 1/imm32/rm32-is-first-inout + 3/imm32/r32-is-first-output + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-xor-lit-with-reg/imm32/next +_Primitive-xor-lit-with-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32 + 0x11/imm32/alloc-id:fake + _string-xor/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_81_subop_xor/imm32/subx-name + 3/imm32/rm32-is-first-output + 0/imm32/no-r32 + 1/imm32/imm32-is-first-inout + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-xor-lit-with-mem/imm32/next +_Primitive-xor-lit-with-mem: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32 + 0x11/imm32/alloc-id:fake + _string-xor-with/imm32/name + 0x11/imm32/alloc-id:fake + Int-var-and-literal/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_81_subop_xor/imm32/subx-name + 1/imm32/rm32-is-first-inout + 0/imm32/no-r32 + 2/imm32/imm32-is-second-inout + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-shift-reg-left-by-lit/imm32/next +_Primitive-shift-reg-left-by-lit: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- shift-left lit => c1/shift 4/subop/left var1/rm32 lit/imm32 + 0x11/imm32/alloc-id:fake + _string-shift-left/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_c1_subop_shift_left/imm32/subx-name + 3/imm32/rm32-is-first-output + 0/imm32/no-r32 + 0/imm32/no-imm32 + 1/imm32/imm8-is-first-inout + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-shift-reg-right-by-lit/imm32/next +_Primitive-shift-reg-right-by-lit: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- shift-right lit => c1/shift 5/subop/right var1/rm32 lit/imm32 + 0x11/imm32/alloc-id:fake + _string-shift-right/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_c1_subop_shift_right_padding_zeroes/imm32/subx-name + 3/imm32/rm32-is-first-output + 0/imm32/no-r32 + 0/imm32/no-imm32 + 1/imm32/imm8-is-first-inout + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-shift-reg-right-signed-by-lit/imm32/next +_Primitive-shift-reg-right-signed-by-lit: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- shift-right-signed lit => c1/shift 7/subop/right-preserving-sign var1/rm32 lit/imm32 + 0x11/imm32/alloc-id:fake + _string-shift-right-signed/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_c1_subop_shift_right_preserving_sign/imm32/subx-name + 3/imm32/rm32-is-first-output + 0/imm32/no-r32 + 0/imm32/no-imm32 + 1/imm32/imm8-is-first-inout + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-shift-mem-left-by-lit/imm32/next +_Primitive-shift-mem-left-by-lit: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # shift-left var1, lit => c1/shift 4/subop/left var1/rm32 lit/imm32 + 0x11/imm32/alloc-id:fake + _string-shift-left/imm32/name + 0x11/imm32/alloc-id:fake + Int-var-and-literal/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_c1_subop_shift_left/imm32/subx-name + 1/imm32/rm32-is-first-inout + 0/imm32/no-r32 + 0/imm32/no-imm32 + 2/imm32/imm8-is-second-inout + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-shift-mem-right-by-lit/imm32/next +_Primitive-shift-mem-right-by-lit: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # shift-right var1, lit => c1/shift 5/subop/right var1/rm32 lit/imm32 + 0x11/imm32/alloc-id:fake + _string-shift-right/imm32/name + 0x11/imm32/alloc-id:fake + Int-var-and-literal/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_c1_subop_shift_right_padding_zeroes/imm32/subx-name + 1/imm32/rm32-is-first-inout + 0/imm32/no-r32 + 0/imm32/no-imm32 + 2/imm32/imm8-is-second-inout + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-shift-mem-right-signed-by-lit/imm32/next +_Primitive-shift-mem-right-signed-by-lit: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # shift-right-signed var1, lit => c1/shift 7/subop/right-preserving-sign var1/rm32 lit/imm32 + 0x11/imm32/alloc-id:fake + _string-shift-right-signed/imm32/name + 0x11/imm32/alloc-id:fake + Int-var-and-literal/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_c1_subop_shift_right_preserving_sign/imm32/subx-name + 1/imm32/rm32-is-first-inout + 0/imm32/no-r32 + 0/imm32/no-imm32 + 2/imm32/imm8-is-second-inout + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-copy-to-eax/imm32/next +# - copy +_Primitive-copy-to-eax: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var/eax <- copy lit => b8/copy-to-eax lit/imm32 + 0x11/imm32/alloc-id:fake + _string-copy/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-eax/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_b8_copy_to_eax/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 1/imm32/imm32-is-first-inout + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-copy-to-ecx/imm32/next +_Primitive-copy-to-ecx: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32 + 0x11/imm32/alloc-id:fake + _string-copy/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-ecx/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_b9_copy_to_ecx/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 1/imm32/imm32-is-first-inout + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-copy-to-edx/imm32/next +_Primitive-copy-to-edx: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var/edx <- copy lit => ba/copy-to-edx lit/imm32 + 0x11/imm32/alloc-id:fake + _string-copy/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-edx/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_ba_copy_to_edx/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 1/imm32/imm32-is-first-inout + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-copy-to-ebx/imm32/next +_Primitive-copy-to-ebx: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32 + 0x11/imm32/alloc-id:fake + _string-copy/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-ebx/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_bb_copy_to_ebx/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 1/imm32/imm32-is-first-inout + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-copy-to-esi/imm32/next +_Primitive-copy-to-esi: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var/esi <- copy lit => be/copy-to-esi lit/imm32 + 0x11/imm32/alloc-id:fake + _string-copy/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-esi/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_be_copy_to_esi/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 1/imm32/imm32-is-first-inout + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-copy-to-edi/imm32/next +_Primitive-copy-to-edi: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var/edi <- copy lit => bf/copy-to-edi lit/imm32 + 0x11/imm32/alloc-id:fake + _string-copy/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-edi/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_bf_copy_to_edi/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 1/imm32/imm32-is-first-inout + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-copy-reg-to-reg/imm32/next +_Primitive-copy-reg-to-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- copy var2/reg => 89/<- var1/rm32 var2/r32 + 0x11/imm32/alloc-id:fake + _string-copy/imm32/name + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_89_<-/imm32/subx-name + 3/imm32/rm32-is-first-output + 1/imm32/r32-is-first-inout + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-copy-reg-to-mem/imm32/next +_Primitive-copy-reg-to-mem: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # copy-to var1 var2/reg => 89/<- var1 var2/r32 + 0x11/imm32/alloc-id:fake + _string-copy-to/imm32/name + 0x11/imm32/alloc-id:fake + Two-args-int-stack-int-reg/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_89_<-/imm32/subx-name + 1/imm32/rm32-is-first-inout + 2/imm32/r32-is-second-inout + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-copy-mem-to-reg/imm32/next +_Primitive-copy-mem-to-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- copy var2 => 8b/-> var2/rm32 var1/r32 + 0x11/imm32/alloc-id:fake + _string-copy/imm32/name + 0x11/imm32/alloc-id:fake + Single-int-var-in-mem/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_8b_->/imm32/subx-name + 1/imm32/rm32-is-first-inout + 3/imm32/r32-is-first-output + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-copy-lit-to-reg/imm32/next +_Primitive-copy-lit-to-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32 + 0x11/imm32/alloc-id:fake + _string-copy/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_c7_subop_copy/imm32/subx-name + 3/imm32/rm32-is-first-output + 0/imm32/no-r32 + 1/imm32/imm32-is-first-inout + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-copy-lit-to-mem/imm32/next +_Primitive-copy-lit-to-mem: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32 + 0x11/imm32/alloc-id:fake + _string-copy-to/imm32/name + 0x11/imm32/alloc-id:fake + Int-var-and-literal/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_c7_subop_copy/imm32/subx-name + 1/imm32/rm32-is-first-inout + 0/imm32/no-r32 + 2/imm32/imm32-is-second-inout + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-copy-byte-from-reg/imm32/next +# - copy byte +_Primitive-copy-byte-from-reg: + 0x11/imm32/alloc-id:fake:payload + # var/reg <- copy-byte var2/reg2 => 8a/byte-> %var2 var/r32 + 0x11/imm32/alloc-id:fake + _string-copy-byte/imm32/name + 0x11/imm32/alloc-id:fake + Single-byte-var-in-some-register/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-byte-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_8a_copy_byte/imm32/subx-name + 1/imm32/rm32-is-first-inout + 3/imm32/r32-is-first-output + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-copy-byte-from-mem/imm32/next +_Primitive-copy-byte-from-mem: + 0x11/imm32/alloc-id:fake:payload + # var/reg <- copy-byte *var2/reg2 => 8a/byte-> *var2 var/r32 + 0x11/imm32/alloc-id:fake + _string-copy-byte/imm32/name + 0x11/imm32/alloc-id:fake + Single-byte-var-in-mem/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-byte-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_8a_copy_byte/imm32/subx-name + 1/imm32/rm32-is-first-inout + 3/imm32/r32-is-first-output + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-copy-byte-to-mem/imm32/next +_Primitive-copy-byte-to-mem: + 0x11/imm32/alloc-id:fake:payload + # copy-byte-to *var1/reg1, var2/reg2 => 88/byte<- *reg1 reg2/r32 + 0x11/imm32/alloc-id:fake + _string-copy-byte-to/imm32/name + 0x11/imm32/alloc-id:fake + Two-args-byte-stack-byte-reg/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_88_copy_byte/imm32/subx-name + 1/imm32/rm32-is-first-inout + 2/imm32/r32-is-second-inout + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-address/imm32/next +# - address +_Primitive-address: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- address var2 => 8d/copy-address var2/rm32 var1/r32 + 0x11/imm32/alloc-id:fake + _string-address/imm32/name + 0x11/imm32/alloc-id:fake + Single-int-var-in-mem/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-addr-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_8d_copy_address/imm32/subx-name + 1/imm32/rm32-is-first-inout + 3/imm32/r32-is-first-output + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-compare-reg-with-reg/imm32/next +# - compare +_Primitive-compare-reg-with-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # compare var1/reg1 var2/reg2 => 39/compare var1/rm32 var2/r32 + 0x11/imm32/alloc-id:fake + _string-compare/imm32/name + 0x11/imm32/alloc-id:fake + Two-int-args-in-regs/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_39_compare->/imm32/subx-name + 1/imm32/rm32-is-first-inout + 2/imm32/r32-is-second-inout + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-compare-mem-with-reg/imm32/next +_Primitive-compare-mem-with-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # compare var1 var2/reg => 39/compare var1/rm32 var2/r32 + 0x11/imm32/alloc-id:fake + _string-compare/imm32/name + 0x11/imm32/alloc-id:fake + Two-args-int-stack-int-reg/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_39_compare->/imm32/subx-name + 1/imm32/rm32-is-first-inout + 2/imm32/r32-is-second-inout + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-compare-reg-with-mem/imm32/next +_Primitive-compare-reg-with-mem: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # compare var1/reg var2 => 3b/compare<- var2/rm32 var1/r32 + 0x11/imm32/alloc-id:fake + _string-compare/imm32/name + 0x11/imm32/alloc-id:fake + Two-args-int-reg-int-stack/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_3b_compare<-/imm32/subx-name + 2/imm32/rm32-is-second-inout + 1/imm32/r32-is-first-inout + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-compare-eax-with-literal/imm32/next +_Primitive-compare-eax-with-literal: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # compare var1/eax n => 3d/compare-eax-with n/imm32 + 0x11/imm32/alloc-id:fake + _string-compare/imm32/name + 0x11/imm32/alloc-id:fake + Two-args-int-eax-int-literal/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_3d_compare_eax_with/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 2/imm32/imm32-is-second-inout + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-compare-reg-with-literal/imm32/next +_Primitive-compare-reg-with-literal: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # compare var1/reg n => 81 7/subop/compare %reg n/imm32 + 0x11/imm32/alloc-id:fake + _string-compare/imm32/name + 0x11/imm32/alloc-id:fake + Int-var-in-register-and-literal/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_81_subop_compare/imm32/subx-name + 1/imm32/rm32-is-first-inout + 0/imm32/no-r32 + 2/imm32/imm32-is-second-inout + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-compare-mem-with-literal/imm32/next +_Primitive-compare-mem-with-literal: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # compare var1 n => 81 7/subop/compare *(ebp+___) n/imm32 + 0x11/imm32/alloc-id:fake + _string-compare/imm32/name + 0x11/imm32/alloc-id:fake + Int-var-and-literal/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_81_subop_compare/imm32/subx-name + 1/imm32/rm32-is-first-inout + 0/imm32/no-r32 + 2/imm32/imm32-is-second-inout + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-negate-reg/imm32/next +# - negate +_Primitive-negate-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- negate => f7 3/subop/negate var1/rm32 + 0x11/imm32/alloc-id:fake + _string-negate/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_f7_subop_negate/imm32/subx-name + 3/imm32/rm32-is-first-output + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-negate-mem/imm32/next +_Primitive-negate-mem: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # negate var1 => f7 3/subop/negate var1/rm32 + 0x11/imm32/alloc-id:fake + _string-negate/imm32/name + 0x11/imm32/alloc-id:fake + Single-int-var-in-mem/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_f7_subop_negate/imm32/subx-name + 1/imm32/rm32-is-first-inout + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-multiply-reg-by-reg/imm32/next +# - multiply +_Primitive-multiply-reg-by-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32 + 0x11/imm32/alloc-id:fake + _string-multiply/imm32/name + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_0f_af_multiply/imm32/subx-name + 1/imm32/rm32-is-first-inout + 3/imm32/r32-is-first-output + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-multiply-reg-by-mem/imm32/next +_Primitive-multiply-reg-by-mem: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32 + 0x11/imm32/alloc-id:fake + _string-multiply/imm32/name + 0x11/imm32/alloc-id:fake + Single-int-var-in-mem/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_0f_af_multiply/imm32/subx-name + 1/imm32/rm32-is-first-inout + 3/imm32/r32-is-first-output + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-convert-mem-to-xreg/imm32/next +# - convert int to floating point +_Primitive-convert-mem-to-xreg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/xreg <- convert var2 => f3 0f 2a/convert-to-float var2/rm32 var1/x32 + 0x11/imm32/alloc-id:fake + _string-convert/imm32/name + 0x11/imm32/alloc-id:fake + Single-int-var-in-mem/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_f3_0f_2a_convert_to_float/imm32/subx-name + 1/imm32/rm32-is-first-inout + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 3/imm32/x32-is-first-output + 0x11/imm32/alloc-id:fake + _Primitive-convert-reg-to-xreg/imm32/next +_Primitive-convert-reg-to-xreg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/xreg <- convert var2/reg => f3 0f 2a/convert-to-float var2/rm32 var1/x32 + 0x11/imm32/alloc-id:fake + _string-convert/imm32/name + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_f3_0f_2a_convert_to_float/imm32/subx-name + 1/imm32/rm32-is-first-inout + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 3/imm32/x32-is-first-output + 0x11/imm32/alloc-id:fake + _Primitive-convert-xmem-to-reg/imm32/next +# - convert floating point to int +_Primitive-convert-xmem-to-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- convert var2 => f3 0f 2d/convert-to-int var2/xm32 var1/r32 + 0x11/imm32/alloc-id:fake + _string-convert/imm32/name + 0x11/imm32/alloc-id:fake + Single-float-var-in-mem/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_f3_0f_2d_convert_to_int/imm32/subx-name + 0/imm32/no-rm32 + 3/imm32/r32-is-first-output + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 1/imm32/xm32-is-first-inout + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-convert-xreg-to-reg/imm32/next +_Primitive-convert-xreg-to-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- convert var2/xreg => f3 0f 2d/convert-to-int var2/xm32 var1/r32 + 0x11/imm32/alloc-id:fake + _string-convert/imm32/name + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_f3_0f_2d_convert_to_int/imm32/subx-name + 0/imm32/no-rm32 + 3/imm32/r32-is-first-output + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 1/imm32/xm32-is-first-inout + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-truncate-xmem-to-reg/imm32/next +_Primitive-truncate-xmem-to-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- truncate var2 => f3 0f 2c/truncate-to-int var2/xm32 var1/r32 + 0x11/imm32/alloc-id:fake + _string-truncate/imm32/name + 0x11/imm32/alloc-id:fake + Single-float-var-in-mem/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_f3_0f_2c_truncate_to_int/imm32/subx-name + 0/imm32/no-rm32 + 3/imm32/r32-is-first-output + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 1/imm32/xm32-is-first-inout + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-truncate-xreg-to-reg/imm32/next +_Primitive-truncate-xreg-to-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- truncate var2/xreg => f3 0f 2c/truncate-to-int var2/xm32 var1/r32 + 0x11/imm32/alloc-id:fake + _string-truncate/imm32/name + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_f3_0f_2c_truncate_to_int/imm32/subx-name + 0/imm32/no-rm32 + 3/imm32/r32-is-first-output + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 1/imm32/xm32-is-first-inout + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-reinterpret-xmem-as-reg/imm32/next +# - reinterpret bytes (just for debugging) +_Primitive-reinterpret-xmem-as-reg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- reinterpret var2 => 8b/-> var2/xm32 var1/r32 + 0x11/imm32/alloc-id:fake + _string-reinterpret/imm32/name + 0x11/imm32/alloc-id:fake + Single-float-var-in-mem/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_8b_->/imm32/subx-name + 0/imm32/no-rm32 + 3/imm32/r32-is-first-output + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 1/imm32/xm32-is-first-inout + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-reinterpret-mem-as-xreg/imm32/next +_Primitive-reinterpret-mem-as-xreg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/xreg <- reinterpret var2 => f3 0f 10/-> var2/rm32 var1/x32 + 0x11/imm32/alloc-id:fake + _string-reinterpret/imm32/name + 0x11/imm32/alloc-id:fake + Single-int-var-in-mem/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_f3_0f_10_copy/imm32/subx-name + 1/imm32/rm32-is-first-inout + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 3/imm32/x32-is-first-output + 0x11/imm32/alloc-id:fake + _Primitive-copy-xreg-to-xreg/imm32/next +# - floating-point copy +_Primitive-copy-xreg-to-xreg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/xreg <- copy var2/xreg => f3 0f 11/<- var1/xm32 var2/x32 + 0x11/imm32/alloc-id:fake + _string-copy/imm32/name + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_f3_0f_11_copy/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 3/imm32/xm32-is-first-output + 1/imm32/x32-is-first-inout + 0x11/imm32/alloc-id:fake + _Primitive-copy-xreg-to-mem/imm32/next +_Primitive-copy-xreg-to-mem: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # copy-to var1 var2/xreg => f3 0f 11/<- var1 var2/x32 + 0x11/imm32/alloc-id:fake + _string-copy-to/imm32/name + 0x11/imm32/alloc-id:fake + Two-args-float-stack-float-reg/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_f3_0f_11_copy/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 1/imm32/xm32-is-first-inout + 2/imm32/x32-is-second-inout + 0x11/imm32/alloc-id:fake + _Primitive-copy-mem-to-xreg/imm32/next +_Primitive-copy-mem-to-xreg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/xreg <- copy var2 => f3 0f 10/-> var2/rm32 var1/x32 + 0x11/imm32/alloc-id:fake + _string-copy/imm32/name + 0x11/imm32/alloc-id:fake + Single-float-var-in-mem/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_f3_0f_10_copy/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 1/imm32/xm32-is-first-inout + 3/imm32/x32-is-first-output + 0x11/imm32/alloc-id:fake + _Primitive-address-of-xmem/imm32/next +# - floating-point-address +_Primitive-address-of-xmem: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/reg <- address var2 => 8d/copy-address var2/rm32 var1/r32 + 0x11/imm32/alloc-id:fake + _string-address/imm32/name + 0x11/imm32/alloc-id:fake + Single-float-var-in-mem/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-addr-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_8d_copy_address/imm32/subx-name + 1/imm32/rm32-is-first-inout + 3/imm32/r32-is-first-output + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-add-xreg-to-xreg/imm32/next +# - floating-point add +_Primitive-add-xreg-to-xreg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/xreg <- add var2/xreg => f3 0f 58/add var1/xm32 var2/x32 + 0x11/imm32/alloc-id:fake + _string-add/imm32/name + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_f3_0f_58_add/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 1/imm32/xm32-is-first-inout + 3/imm32/x32-is-first-output + 0x11/imm32/alloc-id:fake + _Primitive-add-mem-to-xreg/imm32/next +_Primitive-add-mem-to-xreg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/xreg <- add var2 => f3 0f 58/add var2/xm32 var1/x32 + 0x11/imm32/alloc-id:fake + _string-add/imm32/name + 0x11/imm32/alloc-id:fake + Single-float-var-in-mem/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_f3_0f_58_add/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 1/imm32/xm32-is-first-inout + 3/imm32/x32-is-first-output + 0x11/imm32/alloc-id:fake + _Primitive-subtract-xreg-from-xreg/imm32/next +# - floating-point subtract +_Primitive-subtract-xreg-from-xreg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/xreg <- subtract var2/xreg => f3 0f 5c/subtract var1/xm32 var2/x32 + 0x11/imm32/alloc-id:fake + _string-subtract/imm32/name + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_f3_0f_5c_subtract/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 1/imm32/xm32-is-first-inout + 3/imm32/x32-is-first-output + 0x11/imm32/alloc-id:fake + _Primitive-subtract-mem-from-xreg/imm32/next +_Primitive-subtract-mem-from-xreg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/xreg <- subtract var2 => f3 0f 5c/subtract var2/xm32 var1/x32 + 0x11/imm32/alloc-id:fake + _string-subtract/imm32/name + 0x11/imm32/alloc-id:fake + Single-float-var-in-mem/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_f3_0f_5c_subtract/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 1/imm32/xm32-is-first-inout + 3/imm32/x32-is-first-output + 0x11/imm32/alloc-id:fake + _Primitive-multiply-xreg-by-xreg/imm32/next +# - floating-point multiply +_Primitive-multiply-xreg-by-xreg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/xreg <- multiply var2 => f3 0f 59/multiply var2/xm32 var1/x32 + 0x11/imm32/alloc-id:fake + _string-multiply/imm32/name + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_f3_0f_59_multiply/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 1/imm32/xm32-is-first-inout + 3/imm32/x32-is-first-output + 0x11/imm32/alloc-id:fake + _Primitive-multiply-xreg-by-mem/imm32/next +_Primitive-multiply-xreg-by-mem: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/xreg <- multiply var2 => 53 0f 59/multiply var2/xm32 var1/x32 + 0x11/imm32/alloc-id:fake + _string-multiply/imm32/name + 0x11/imm32/alloc-id:fake + Single-float-var-in-mem/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_f3_0f_59_multiply/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 1/imm32/xm32-is-first-inout + 3/imm32/x32-is-first-output + 0x11/imm32/alloc-id:fake + _Primitive-divide-xreg-by-xreg/imm32/next +# - floating-point divide +_Primitive-divide-xreg-by-xreg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/xreg <- divide var2 => f3 0f 5e/divide var2/xm32 var1/x32 + 0x11/imm32/alloc-id:fake + _string-divide/imm32/name + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_f3_0f_5e_divide/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 1/imm32/xm32-is-first-inout + 3/imm32/x32-is-first-output + 0x11/imm32/alloc-id:fake + _Primitive-divide-xreg-by-mem/imm32/next +_Primitive-divide-xreg-by-mem: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/xreg <- divide var2 => f3 0f 5e/divide var2/xm32 var1/x32 + 0x11/imm32/alloc-id:fake + _string-divide/imm32/name + 0x11/imm32/alloc-id:fake + Single-float-var-in-mem/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_f3_0f_5e_divide/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 1/imm32/xm32-is-first-inout + 3/imm32/x32-is-first-output + 0x11/imm32/alloc-id:fake + _Primitive-max-xreg-with-xreg/imm32/next +# - floating-point maximum +_Primitive-max-xreg-with-xreg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/xreg <- max var2 => f3 0f 5f/max var2/xm32 var1/x32 + 0x11/imm32/alloc-id:fake + _string-max/imm32/name + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_f3_0f_5f_max/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 1/imm32/xm32-is-first-inout + 3/imm32/x32-is-first-output + 0x11/imm32/alloc-id:fake + _Primitive-max-xreg-with-mem/imm32/next +_Primitive-max-xreg-with-mem: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/xreg <- divide var2 => f3 0f 5f/max var2/xm32 var1/x32 + 0x11/imm32/alloc-id:fake + _string-max/imm32/name + 0x11/imm32/alloc-id:fake + Single-float-var-in-mem/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_f3_0f_5f_max/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 1/imm32/xm32-is-first-inout + 3/imm32/x32-is-first-output + 0x11/imm32/alloc-id:fake + _Primitive-min-xreg-with-xreg/imm32/next +# - floating-point minimum +_Primitive-min-xreg-with-xreg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/xreg <- divide var2 => f3 0f 5d/min var2/xm32 var1/x32 + 0x11/imm32/alloc-id:fake + _string-min/imm32/name + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_f3_0f_5d_min/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 1/imm32/xm32-is-first-inout + 3/imm32/x32-is-first-output + 0x11/imm32/alloc-id:fake + _Primitive-min-xreg-with-mem/imm32/next +_Primitive-min-xreg-with-mem: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/xreg <- divide var2 => f3 0f 5d/min var2/xm32 var1/x32 + 0x11/imm32/alloc-id:fake + _string-min/imm32/name + 0x11/imm32/alloc-id:fake + Single-float-var-in-mem/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_f3_0f_5d_min/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 1/imm32/xm32-is-first-inout + 3/imm32/x32-is-first-output + 0x11/imm32/alloc-id:fake + _Primitive-reciprocal-xreg-to-xreg/imm32/next +# - floating-point reciprocal +_Primitive-reciprocal-xreg-to-xreg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/xreg <- reciprocal var2 => f3 0f 53/reciprocal var2/xm32 var1/x32 + 0x11/imm32/alloc-id:fake + _string-reciprocal/imm32/name + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_f3_0f_53_reciprocal/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 1/imm32/xm32-is-first-inout + 3/imm32/x32-is-first-output + 0x11/imm32/alloc-id:fake + _Primitive-reciprocal-mem-to-xreg/imm32/next +_Primitive-reciprocal-mem-to-xreg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/xreg <- divide var2 => f3 0f 53/reciprocal var2/xm32 var1/x32 + 0x11/imm32/alloc-id:fake + _string-reciprocal/imm32/name + 0x11/imm32/alloc-id:fake + Single-float-var-in-mem/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_f3_0f_53_reciprocal/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 1/imm32/xm32-is-first-inout + 3/imm32/x32-is-first-output + 0x11/imm32/alloc-id:fake + _Primitive-square-root-xreg-to-xreg/imm32/next +# - floating-point square root +_Primitive-square-root-xreg-to-xreg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/xreg <- square-root var2 => f3 0f 51/square-root var2/xm32 var1/x32 + 0x11/imm32/alloc-id:fake + _string-square-root/imm32/name + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_f3_0f_51_square_root/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 1/imm32/xm32-is-first-inout + 3/imm32/x32-is-first-output + 0x11/imm32/alloc-id:fake + _Primitive-square-root-mem-to-xreg/imm32/next +_Primitive-square-root-mem-to-xreg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/xreg <- divide var2 => f3 0f 51/square-root var2/xm32 var1/x32 + 0x11/imm32/alloc-id:fake + _string-square-root/imm32/name + 0x11/imm32/alloc-id:fake + Single-float-var-in-mem/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_f3_0f_51_square_root/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 1/imm32/xm32-is-first-inout + 3/imm32/x32-is-first-output + 0x11/imm32/alloc-id:fake + _Primitive-inverse-square-root-xreg-to-xreg/imm32/next +# - floating-point inverse square root 1/sqrt(x) +_Primitive-inverse-square-root-xreg-to-xreg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/xreg <- reciprocal var2 => f3 0f 52/inverse-square-root var2/xm32 var1/x32 + 0x11/imm32/alloc-id:fake + _string-inverse-square-root/imm32/name + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_f3_0f_52_inverse_square_root/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 1/imm32/xm32-is-first-inout + 3/imm32/x32-is-first-output + 0x11/imm32/alloc-id:fake + _Primitive-inverse-square-root-mem-to-xreg/imm32/next +_Primitive-inverse-square-root-mem-to-xreg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # var1/xreg <- divide var2 => f3 0f 52/inverse-square-root var2/xm32 var1/x32 + 0x11/imm32/alloc-id:fake + _string-inverse-square-root/imm32/name + 0x11/imm32/alloc-id:fake + Single-float-var-in-mem/imm32/inouts + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/outputs + 0x11/imm32/alloc-id:fake + _string_f3_0f_52_inverse_square_root/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 1/imm32/xm32-is-first-inout + 3/imm32/x32-is-first-output + 0x11/imm32/alloc-id:fake + _Primitive-compare-xreg-with-xreg/imm32/next +# - floating-point compare +_Primitive-compare-xreg-with-xreg: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # compare var1/reg1 var2/reg2 => 0f 2f/compare var2/x32 var1/xm32 + 0x11/imm32/alloc-id:fake + _string-compare/imm32/name + 0x11/imm32/alloc-id:fake + Two-float-args-in-regs/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_2f_compare/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 2/imm32/xm32-is-second-inout + 1/imm32/x32-is-first-inout + 0x11/imm32/alloc-id:fake + _Primitive-compare-xreg-with-mem/imm32/next +_Primitive-compare-xreg-with-mem: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + # compare var1/xreg var2 => 0f 2f/compare var1/x32 var2/xm32 + 0x11/imm32/alloc-id:fake + _string-compare/imm32/name + 0x11/imm32/alloc-id:fake + Two-args-float-reg-float-stack/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_2f_compare/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 2/imm32/xm32-is-second-inout + 1/imm32/x32-is-first-inout + 0x11/imm32/alloc-id:fake + _Primitive-break-if-addr</imm32/next +# - branches +_Primitive-break-if-addr<: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if-addr</imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_82_jump_break/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if-addr>=/imm32/next +_Primitive-break-if-addr>=: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if-addr>=/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_83_jump_break/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if-=/imm32/next +_Primitive-break-if-=: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if-=/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_84_jump_break/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if-!=/imm32/next +_Primitive-break-if-!=: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if-!=/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_85_jump_break/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if-addr<=/imm32/next +_Primitive-break-if-addr<=: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if-addr<=/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_86_jump_break/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if-addr>/imm32/next +_Primitive-break-if-addr>: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if-addr>/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_87_jump_break/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if-</imm32/next +_Primitive-break-if-<: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if-</imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_8c_jump_break/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if->=/imm32/next +_Primitive-break-if->=: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if->=/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_8d_jump_break/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if-<=/imm32/next +_Primitive-break-if-<=: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if-<=/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_8e_jump_break/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if->/imm32/next +_Primitive-break-if->: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if->/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_8f_jump_break/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break/imm32/next +_Primitive-break: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_e9_jump_break/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if-addr</imm32/next +_Primitive-loop-if-addr<: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if-addr</imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_82_jump_loop/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if-addr>=/imm32/next +_Primitive-loop-if-addr>=: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if-addr>=/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_83_jump_loop/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if-=/imm32/next +_Primitive-loop-if-=: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if-=/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_84_jump_loop/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if-!=/imm32/next +_Primitive-loop-if-!=: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if-!=/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_85_jump_loop/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if-addr<=/imm32/next +_Primitive-loop-if-addr<=: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if-addr<=/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_86_jump_loop/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if-addr>/imm32/next +_Primitive-loop-if-addr>: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if-addr>/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_87_jump_loop/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if-</imm32/next +_Primitive-loop-if-<: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if-</imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_8c_jump_loop/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if->=/imm32/next +_Primitive-loop-if->=: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if->=/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_8d_jump_loop/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if-<=/imm32/next +_Primitive-loop-if-<=: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if-<=/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_8e_jump_loop/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if->/imm32/next +_Primitive-loop-if->: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if->/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_8f_jump_loop/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop/imm32/next # we probably don't need an unconditional break +_Primitive-loop: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_e9_jump_loop/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if-addr<-named/imm32/next +# - branches to named blocks +_Primitive-break-if-addr<-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if-addr</imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_82_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if-addr>=-named/imm32/next +_Primitive-break-if-addr>=-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if-addr>=/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_83_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if-=-named/imm32/next +_Primitive-break-if-=-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if-=/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_84_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if-!=-named/imm32/next +_Primitive-break-if-!=-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if-!=/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_85_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if-addr<=-named/imm32/next +_Primitive-break-if-addr<=-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if-addr<=/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_86_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if-addr>-named/imm32/next +_Primitive-break-if-addr>-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if-addr>/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_87_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if-<-named/imm32/next +_Primitive-break-if-<-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if-</imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_8c_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if->=-named/imm32/next +_Primitive-break-if->=-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if->=/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_8d_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if-<=-named/imm32/next +_Primitive-break-if-<=-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if-<=/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_8e_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if->-named/imm32/next +_Primitive-break-if->-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if->/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_8f_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-named/imm32/next +_Primitive-break-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_e9_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if-addr<-named/imm32/next +_Primitive-loop-if-addr<-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if-addr</imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_82_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if-addr>=-named/imm32/next +_Primitive-loop-if-addr>=-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if-addr>=/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_83_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if-=-named/imm32/next +_Primitive-loop-if-=-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if-=/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_84_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if-!=-named/imm32/next +_Primitive-loop-if-!=-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if-!=/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_85_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if-addr<=-named/imm32/next +_Primitive-loop-if-addr<=-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if-addr<=/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_86_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if-addr>-named/imm32/next +_Primitive-loop-if-addr>-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if-addr>/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_87_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if-<-named/imm32/next +_Primitive-loop-if-<-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if-</imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_8c_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if->=-named/imm32/next +_Primitive-loop-if->=-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if->=/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_8d_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if-<=-named/imm32/next +_Primitive-loop-if-<=-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if-<=/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_8e_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if->-named/imm32/next +_Primitive-loop-if->-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if->/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_8f_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-named/imm32/next # we probably don't need an unconditional break +_Primitive-loop-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_e9_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if-float</imm32/next +# - branches based on floating-point comparisons +_Primitive-break-if-float<: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if-float</imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_82_jump_break/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if-float>=/imm32/next +_Primitive-break-if-float>=: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if-float>=/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_83_jump_break/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if-float<=/imm32/next +_Primitive-break-if-float<=: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if-float<=/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_86_jump_break/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if-float>/imm32/next +_Primitive-break-if-float>: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if-float>/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_87_jump_break/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if-float</imm32/next +_Primitive-loop-if-float<: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if-float</imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_82_jump_loop/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if-float>=/imm32/next +_Primitive-loop-if-float>=: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if-float>=/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_83_jump_loop/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if-float<=/imm32/next +_Primitive-loop-if-float<=: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if-float<=/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_86_jump_loop/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if-float>/imm32/next +_Primitive-loop-if-float>: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if-float>/imm32/name + 0/imm32/no-inouts + 0/imm32/no-inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_87_jump_loop/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 0/imm32/no-disp32 + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if-float<-named/imm32/next +_Primitive-break-if-float<-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if-float</imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_82_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if-float>=-named/imm32/next +_Primitive-break-if-float>=-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if-float>=/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_83_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if-float<=-named/imm32/next +_Primitive-break-if-float<=-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if-float<=/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_86_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-break-if-float>-named/imm32/next +_Primitive-break-if-float>-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-break-if-float>/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_87_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if-float<-named/imm32/next +_Primitive-loop-if-float<-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if-float</imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_82_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if-float>=-named/imm32/next +_Primitive-loop-if-float>=-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if-float>=/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_83_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if-float<=-named/imm32/next +_Primitive-loop-if-float<=-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if-float<=/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_86_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0x11/imm32/alloc-id:fake + _Primitive-loop-if-float>-named/imm32/next +_Primitive-loop-if-float>-named: # (payload primitive) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + _string-loop-if-float>/imm32/name + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/inouts + 0/imm32/no-outputs + 0/imm32/no-outputs + 0x11/imm32/alloc-id:fake + _string_0f_87_jump_label/imm32/subx-name + 0/imm32/no-rm32 + 0/imm32/no-r32 + 0/imm32/no-imm32 + 0/imm32/no-imm8 + 1/imm32/disp32-is-first-inout + 0/imm32/no-xm32 + 0/imm32/no-x32 + 0/imm32/next + 0/imm32/next + +# string literals for Mu instructions +_string-add: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "add" + 0x3/imm32/size + 0x61/a 0x64/d 0x64/d +_string-address: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "address" + 0x7/imm32/size + 0x61/a 0x64/d 0x64/d 0x72/r 0x65/e 0x73/s 0x73/s +_string-add-to: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "add-to" + 0x6/imm32/size + 0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o +_string-and: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "and" + 0x3/imm32/size + 0x61/a 0x6e/n 0x64/d +_string-and-with: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "and-with" + 0x8/imm32/size + 0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h +_string-break: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "break" + 0x5/imm32/size + 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k +_string-break-if-<: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "break-if-<" + 0xa/imm32/size + 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< +_string-break-if-<=: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "break-if-<=" + 0xb/imm32/size + 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/= +_string-break-if-=: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "break-if-=" + 0xa/imm32/size + 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/= +_string-break-if->: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "break-if->" + 0xa/imm32/size + 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> +_string-break-if->=: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "break-if->=" + 0xb/imm32/size + 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/= +_string-break-if-!=: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "break-if-!=" + 0xb/imm32/size + 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/= +_string-break-if-addr<: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "break-if-addr<" + 0xe/imm32/size + 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/< +_string-break-if-addr<=: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "break-if-addr<=" + 0xf/imm32/size + 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/= +_string-break-if-addr>: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "break-if-addr>" + 0xe/imm32/size + 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/> +_string-break-if-addr>=: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "break-if-addr>=" + 0xf/imm32/size + 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/= +_string-break-if-float<: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "break-if-float<" + 0xf/imm32/size + 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/< +_string-break-if-float<=: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "break-if-float<=" + 0x10/imm32/size + 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/= +_string-break-if-float>: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "break-if-float>" + 0xf/imm32/size + 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/> +_string-break-if-float>=: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "break-if-float>=" + 0x10/imm32/size + 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/= +_string-compare: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "compare" + 0x7/imm32/size + 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e +_string-copy: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "copy" + 0x4/imm32/size + 0x63/c 0x6f/o 0x70/p 0x79/y +_string-copy-to: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "copy-to" + 0x7/imm32/size + 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o +_string-copy-byte: + 0x11/imm32/alloc-id:fake:payload + # "copy-byte" + 0x9/imm32/size + 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e +_string-copy-byte-to: + 0x11/imm32/alloc-id:fake:payload + # "copy-byte-to" + 0xc/imm32/size + 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x74/t 0x6f/o +_string-decrement: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "decrement" + 0x9/imm32/size + 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t +_string-increment: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "increment" + 0x9/imm32/size + 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t +_string-loop: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "loop" + 0x4/imm32/size + 0x6c/l 0x6f/o 0x6f/o 0x70/p +_string-loop-if-<: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "loop-if-<" + 0x9/imm32/size + 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< +_string-loop-if-<=: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "loop-if-<=" + 0xa/imm32/size + 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/= +_string-loop-if-=: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "loop-if-=" + 0x9/imm32/size + 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/= +_string-loop-if->: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "loop-if->" + 0x9/imm32/size + 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> +_string-loop-if->=: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "loop-if->=" + 0xa/imm32/size + 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/= +_string-loop-if-!=: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "loop-if-!=" + 0xa/imm32/size + 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/= +_string-loop-if-addr<: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "loop-if-addr<" + 0xd/imm32/size + 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/< +_string-loop-if-addr<=: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "loop-if-addr<=" + 0xe/imm32/size + 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/= +_string-loop-if-addr>: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "loop-if-addr>" + 0xd/imm32/size + 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/> +_string-loop-if-addr>=: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "loop-if-addr>=" + 0xe/imm32/size + 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/= +_string-loop-if-float<: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "loop-if-float<" + 0xe/imm32/size + 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/< +_string-loop-if-float<=: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "loop-if-float<=" + 0xf/imm32/size + 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/= +_string-loop-if-float>: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "loop-if-float>" + 0xe/imm32/size + 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/> +_string-loop-if-float>=: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "loop-if-float>=" + 0xf/imm32/size + 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/= +_string-multiply: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "multiply" + 0x8/imm32/size + 0x6d/m 0x75/u 0x6c/l 0x74/t 0x69/i 0x70/p 0x6c/l 0x79/y +_string-convert: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "convert" + 0x7/imm32/size + 0x63/c 0x6f/o 0x6e/n 0x76/v 0x65/e 0x72/r 0x74/t +_string-truncate: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "truncate" + 0x8/imm32/size + 0x74/t 0x72/r 0x75/u 0x6e/n 0x63/c 0x61/a 0x74/t 0x65/e +_string-reinterpret: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "reinterpret" + 0xb/imm32/size + 0x72/r 0x65/e 0x69/i 0x6e/n 0x74/t 0x65/e 0x72/r 0x70/p 0x72/r 0x65/e 0x74/t +_string-divide: + 0x11/imm32/alloc-id:fake:payload + # "divide" + 0x6/imm32/size + 0x64/d 0x69/i 0x76/v 0x69/i 0x64/d 0x65/e +_string-max: + 0x11/imm32/alloc-id:fake:payload + # "max" + 0x3/imm32/size + 0x6d/m 0x61/a 0x78/x +_string-min: + 0x11/imm32/alloc-id:fake:payload + # "min" + 0x3/imm32/size + 0x6d/m 0x69/i 0x6e/n +_string-reciprocal: + 0x11/imm32/alloc-id:fake:payload + # "reciprocal" + 0xa/imm32/size + 0x72/r 0x65/e 0x63/c 0x69/i 0x70/p 0x72/r 0x6f/o 0x63/c 0x61/a 0x6c/l +_string-square-root: + 0x11/imm32/alloc-id:fake:payload + # "square-root" + 0xb/imm32/size + 0x73/s 0x71/q 0x75/u 0x61/a 0x72/r 0x65/e 0x2d/- 0x72/r 0x6f/o 0x6f/o 0x74/t +_string-inverse-square-root: + 0x11/imm32/alloc-id:fake:payload + # "inverse-square-root" + 0x13/imm32/size + 0x69/i 0x6e/n 0x76/v 0x65/e 0x72/r 0x73/s 0x65/e 0x2d/- 0x73/s 0x71/q 0x75/u 0x61/a 0x72/r 0x65/e 0x2d/- 0x72/r 0x6f/o 0x6f/o 0x74/t +_string-negate: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "negate" + 0x6/imm32/size + 0x6e/n 0x65/e 0x67/g 0x61/a 0x74/t 0x65/e +_string-or: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "or" + 0x2/imm32/size + 0x6f/o 0x72/r +_string-or-with: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "or-with" + 0x7/imm32/size + 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h +_string-subtract: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "subtract" + 0x8/imm32/size + 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t +_string-subtract-from: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "subtract-from" + 0xd/imm32/size + 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 +_string-xor: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "xor" + 0x3/imm32/size + 0x78/x 0x6f/o 0x72/r +_string-xor-with: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "xor-with" + 0x8/imm32/size + 0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h +_string-shift-left: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "shift-left" + 0xa/imm32/size + 0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x2d/dash 0x6c/l 0x65/e 0x66/f 0x74/t +_string-shift-right: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "shift-right" + 0xb/imm32/size + 0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x2d/dash 0x72/r 0x69/i 0x67/g 0x68/h 0x74/t +_string-shift-right-signed: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "shift-right-signed" + 0x12/imm32/size + 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 + +# string literals for SubX instructions +_string_01_add_to: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "01/add-to" + 0x9/imm32/size + 0x30/0 0x31/1 0x2f/slash 0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o +_string_03_add: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "03/add" + 0x6/imm32/size + 0x30/0 0x33/3 0x2f/slash 0x61/a 0x64/d 0x64/d +_string_05_add_to_eax: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "05/add-to-eax" + 0xd/imm32/size + 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 +_string_09_or_with: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "09/or-with" + 0xa/imm32/size + 0x30/0 0x39/9 0x2f/slash 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h +_string_0b_or: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0b/or" + 0x5/imm32/size + 0x30/0 0x62/b 0x2f/slash 0x6f/o 0x72/r +_string_0d_or_with_eax: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0d/or-with-eax" + 0xe/imm32/size + 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 +_string_0f_82_jump_label: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 82/jump-if-addr<" + 0x13/imm32/size + 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/< +_string_0f_82_jump_break: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 82/jump-if-addr< break/disp32" + 0x20/imm32/size + 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 +_string_0f_82_jump_loop: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 82/jump-if-addr< loop/disp32" + 0x1f/imm32/size + 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 +_string_0f_83_jump_label: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 83/jump-if-addr>=" + 0x14/imm32/size + 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/= +_string_0f_83_jump_break: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 83/jump-if-addr>= break/disp32" + 0x21/imm32/size + 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 +_string_0f_83_jump_loop: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 83/jump-if-addr>= loop/disp32" + 0x20/imm32/size + 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 +_string_0f_84_jump_label: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 84/jump-if-=" + 0xf/imm32/size + 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/= +_string_0f_84_jump_break: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 84/jump-if-= break/disp32" + 0x1c/imm32/size + 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 +_string_0f_84_jump_loop: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 84/jump-if-= loop/disp32" + 0x1b/imm32/size + 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 +_string_0f_85_jump_label: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 85/jump-if-!=" + 0x10/imm32/size + 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/= +_string_0f_85_jump_break: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 85/jump-if-!= break/disp32" + 0x1d/imm32/size + 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 +_string_0f_85_jump_loop: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 85/jump-if-!= loop/disp32" + 0x1c/imm32/size + 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 +_string_0f_86_jump_label: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 86/jump-if-addr<=" + 0x14/imm32/size + 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/= +_string_0f_86_jump_break: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 86/jump-if-addr<= break/disp32" + 0x21/imm32/size + 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 +_string_0f_86_jump_loop: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 86/jump-if-addr<= loop/disp32" + 0x20/imm32/size + 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 +_string_0f_87_jump_label: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 87/jump-if-addr>" + 0x13/imm32/size + 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/> +_string_0f_87_jump_break: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 87/jump-if-addr> break/disp32" + 0x20/imm32/size + 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 +_string_0f_87_jump_loop: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 87/jump-if-addr> loop/disp32" + 0x1f/imm32/size + 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 +_string_0f_8c_jump_label: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 8c/jump-if-<" + 0xf/imm32/size + 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/< +_string_0f_8c_jump_break: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 8c/jump-if-< break/disp32" + 0x1c/imm32/size + 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 +_string_0f_8c_jump_loop: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 8c/jump-if-< loop/disp32" + 0x1b/imm32/size + 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 +_string_0f_8d_jump_label: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 8d/jump-if->=" + 0x10/imm32/size + 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/= +_string_0f_8d_jump_break: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 8d/jump-if->= break/disp32" + 0x1d/imm32/size + 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 +_string_0f_8d_jump_loop: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 8d/jump-if->= loop/disp32" + 0x1c/imm32/size + 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 +_string_0f_8e_jump_label: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 8e/jump-if-<=" + 0x10/imm32/size + 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/= +_string_0f_8e_jump_break: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 8e/jump-if-<= break/disp32" + 0x1d/imm32/size + 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 +_string_0f_8e_jump_loop: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 8e/jump-if-<= loop/disp32" + 0x1c/imm32/size + 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 +_string_0f_8f_jump_label: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 8f/jump-if->" + 0xf/imm32/size + 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/> +_string_0f_8f_jump_break: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 8f/jump-if-> break/disp32" + 0x1c/imm32/size + 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 +_string_0f_8f_jump_loop: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f 8f/jump-if-> loop/disp32" + 0x1b/imm32/size + 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 +_string_0f_af_multiply: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "0f af/multiply" + 0xe/imm32/size + 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 +_string_f3_0f_2a_convert_to_float: + 0x11/imm32/alloc-id:fake:payload + # "f3 0f 2a/convert-to-float" + 0x19/imm32/size + 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 +_string_f3_0f_2d_convert_to_int: + 0x11/imm32/alloc-id:fake:payload + # "f3 0f 2d/convert-to-int" + 0x17/imm32/size + 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 +_string_f3_0f_2c_truncate_to_int: + 0x11/imm32/alloc-id:fake:payload + # "f3 0f 2c/truncate-to-int" + 0x18/imm32/size + 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 +_string_f3_0f_58_add: + 0x11/imm32/alloc-id:fake:payload + # "f3 0f 58/add" + 0xc/imm32/size + 0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x35/5 0x38/8 0x2f/slash 0x61/a 0x64/d 0x64/d +_string_f3_0f_5c_subtract: + 0x11/imm32/alloc-id:fake:payload + # "f3 0f 5c/subtract" + 0x11/imm32/size + 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 +_string_f3_0f_59_multiply: + 0x11/imm32/alloc-id:fake:payload + # "f3 0f 59/multiply" + 0x11/imm32/size + 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 +_string_f3_0f_5e_divide: + 0x11/imm32/alloc-id:fake:payload + # "f3 0f 5e/divide" + 0xf/imm32/size + 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 +_string_f3_0f_53_reciprocal: + 0x11/imm32/alloc-id:fake:payload + # "f3 0f 53/reciprocal" + 0x13/imm32/size + 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 +_string_f3_0f_51_square_root: + 0x11/imm32/alloc-id:fake:payload + # "f3 0f 51/square-root" + 0x14/imm32/size + 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 +_string_f3_0f_52_inverse_square_root: + 0x11/imm32/alloc-id:fake:payload + # "f3 0f 52/inverse-square-root" + 0x1c/imm32/size + 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 +_string_f3_0f_5d_min: + 0x11/imm32/alloc-id:fake:payload + # "f3 0f 5d/min" + 0xc/imm32/size + 0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x35/5 0x64/d 0x2f/slash 0x6d/m 0x69/i 0x6e/n +_string_f3_0f_5f_max: + 0x11/imm32/alloc-id:fake:payload + # "f3 0f 5f/max" + 0xc/imm32/size + 0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x35/5 0x66/f 0x2f/slash 0x6d/m 0x61/a 0x78/x +_string_f3_0f_10_copy: + 0x11/imm32/alloc-id:fake:payload + # "f3 0f 10/copy" + 0xd/imm32/size + 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 +_string_f3_0f_11_copy: + 0x11/imm32/alloc-id:fake:payload + # "f3 0f 11/copy" + 0xd/imm32/size + 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 +_string_0f_2f_compare: + 0x11/imm32/alloc-id:fake:payload + # "0f 2f/compare" + 0xd/imm32/size + 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 +_string_21_and_with: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "21/and-with" + 0xb/imm32/size + 0x32/2 0x31/1 0x2f/slash 0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h +_string_23_and: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "23/and" + 0x6/imm32/size + 0x32/2 0x33/3 0x2f/slash 0x61/a 0x6e/n 0x64/d +_string_25_and_with_eax: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "25/and-with-eax" + 0xf/imm32/size + 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 +_string_29_subtract_from: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "29/subtract-from" + 0x10/imm32/size + 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 +_string_2b_subtract: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "2b/subtract" + 0xb/imm32/size + 0x32/2 0x62/b 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t +_string_2d_subtract_from_eax: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "2d/subtract-from-eax" + 0x14/imm32/size + 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 +_string_31_xor_with: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "31/xor-with" + 0xb/imm32/size + 0x33/3 0x31/1 0x2f/slash 0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h +_string_33_xor: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "33/xor" + 0x6/imm32/size + 0x33/3 0x33/3 0x2f/slash 0x78/x 0x6f/o 0x72/r +_string_35_xor_with_eax: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "35/xor-with-eax" + 0xf/imm32/size + 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 +_string_39_compare->: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "39/compare->" + 0xc/imm32/size + 0x33/3 0x39/9 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x2d/dash 0x3e/> +_string_3b_compare<-: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "3b/compare<-" + 0xc/imm32/size + 0x33/3 0x62/b 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x3c/< 0x2d/dash +_string_3d_compare_eax_with: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "3d/compare-eax-with" + 0x13/imm32/size + 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 +_string_40_increment_eax: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "40/increment-eax" + 0x10/imm32/size + 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 +_string_41_increment_ecx: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "41/increment-ecx" + 0x10/imm32/size + 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 +_string_42_increment_edx: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "42/increment-edx" + 0x10/imm32/size + 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 +_string_43_increment_ebx: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "43/increment-ebx" + 0x10/imm32/size + 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 +_string_46_increment_esi: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "46/increment-esi" + 0x10/imm32/size + 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 +_string_47_increment_edi: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "47/increment-edi" + 0x10/imm32/size + 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 +_string_48_decrement_eax: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "48/decrement-eax" + 0x10/imm32/size + 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 +_string_49_decrement_ecx: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "49/decrement-ecx" + 0x10/imm32/size + 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 +_string_4a_decrement_edx: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "4a/decrement-edx" + 0x10/imm32/size + 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 +_string_4b_decrement_ebx: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "4b/decrement-ebx" + 0x10/imm32/size + 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 +_string_4e_decrement_esi: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "4e/decrement-esi" + 0x10/imm32/size + 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 +_string_4f_decrement_edi: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "4f/decrement-edi" + 0x10/imm32/size + 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 +_string_81_subop_add: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "81 0/subop/add" + 0xe/imm32/size + 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 +_string_81_subop_or: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "81 1/subop/or" + 0xd/imm32/size + 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 +_string_81_subop_and: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "81 4/subop/and" + 0xe/imm32/size + 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 +_string_81_subop_subtract: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "81 5/subop/subtract" + 0x13/imm32/size + 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 +_string_81_subop_xor: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "81 6/subop/xor" + 0xe/imm32/size + 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 +_string_81_subop_compare: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "81 7/subop/compare" + 0x12/imm32/size + 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 +_string_89_<-: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "89/<-" + 0x5/imm32/size + 0x38/8 0x39/9 0x2f/slash 0x3c/< 0x2d/dash +_string_8b_->: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "8b/->" + 0x5/imm32/size + 0x38/8 0x62/b 0x2f/slash 0x2d/dash 0x3e/> +_string_8a_copy_byte: + 0x11/imm32/alloc-id:fake:payload + # "8a/byte->" + 0x9/imm32/size + 0x38/8 0x61/a 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x3e/> +_string_88_copy_byte: + 0x11/imm32/alloc-id:fake:payload + # "88/byte<-" + 0x9/imm32/size + 0x38/8 0x38/8 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x3c/< 0x2d/- +_string_8d_copy_address: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "8d/copy-address" + 0xf/imm32/size + 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 +_string_b8_copy_to_eax: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "b8/copy-to-eax" + 0xe/imm32/size + 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 +_string_b9_copy_to_ecx: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "b9/copy-to-ecx" + 0xe/imm32/size + 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 +_string_ba_copy_to_edx: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "ba/copy-to-edx" + 0xe/imm32/size + 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 +_string_bb_copy_to_ebx: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "bb/copy-to-ebx" + 0xe/imm32/size + 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 +_string_be_copy_to_esi: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "be/copy-to-esi" + 0xe/imm32/size + 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 +_string_bf_copy_to_edi: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "bf/copy-to-edi" + 0xe/imm32/size + 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 +_string_c7_subop_copy: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "c7 0/subop/copy" + 0xf/imm32/size + 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 +_string_e9_jump_label: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "e9/jump" + 0x7/imm32/size + 0x65/e 0x39/9 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p +_string_e9_jump_break: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "e9/jump break/disp32" + 0x14/imm32/size + 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 +_string_e9_jump_loop: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "e9/jump loop/disp32" + 0x13/imm32/size + 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 +_string_f7_subop_negate: + 0x11/imm32/alloc-id:fake:payload + # "f7 3/subop/negate" + 0x11/imm32/size + 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 +_string_ff_subop_increment: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "ff 0/subop/increment" + 0x14/imm32/size + 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 +_string_ff_subop_decrement: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "ff 1/subop/decrement" + 0x14/imm32/size + 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 +_string_c1_subop_shift_left: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "c1/shift 4/subop/left" + 0x15/imm32/size + 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 +_string_c1_subop_shift_right_padding_zeroes: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "c1/shift 5/subop/right-padding-zeroes" + 0x25/imm32/size + 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 +_string_c1_subop_shift_right_preserving_sign: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + # "c1/shift 7/subop/right-preserving-sign" + 0x26/imm32/size + 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 + +Single-int-var-in-mem: # (payload list var) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + Int-var-in-mem/imm32 + 0/imm32/next + 0/imm32/next + +Int-var-in-mem: # (payload var) + 0x11/imm32/alloc-id:fake:payload + 0/imm32/name + 0/imm32/name + 0x11/imm32/alloc-id:fake + Type-int/imm32 + 1/imm32/some-block-depth + 1/imm32/some-stack-offset + 0/imm32/no-register + 0/imm32/no-register + +# Not really legal, but closest we can currently represent a dereference of an (addr byte) +Single-byte-var-in-mem: # (payload list var) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + Byte-var-in-mem/imm32 + 0/imm32/next + 0/imm32/next + +# Not really legal, but closest we can currently represent a dereference of an (addr byte) +Byte-var-in-mem: # (payload var) + 0x11/imm32/alloc-id:fake:payload + 0/imm32/name + 0/imm32/name + 0x11/imm32/alloc-id:fake + Type-byte/imm32 + 1/imm32/some-block-depth + 1/imm32/some-stack-offset + 0/imm32/no-register + 0/imm32/no-register + +Two-args-int-stack-int-reg: # (payload list var) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + Int-var-in-mem/imm32 + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/next + +Two-int-args-in-regs: # (payload list var) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + Int-var-in-some-register/imm32 + 0x11/imm32/alloc-id:fake + Single-int-var-in-some-register/imm32/next + +# Not really legal, but closest we can currently represent a dereference of an (addr byte) +Two-args-byte-stack-byte-reg: # (payload list var) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + Byte-var-in-mem/imm32 + 0x11/imm32/alloc-id:fake + Single-byte-var-in-some-register/imm32/next + +Two-args-int-reg-int-stack: # (payload list var) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + Int-var-in-some-register/imm32 + 0x11/imm32/alloc-id:fake + Single-int-var-in-mem/imm32/next + +Two-args-int-eax-int-literal: # (payload list var) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + Int-var-in-eax/imm32 + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/next + +Int-var-and-literal: # (payload list var) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + Int-var-in-mem/imm32 + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/next + +Int-var-in-register-and-literal: # (payload list var) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + Int-var-in-some-register/imm32 + 0x11/imm32/alloc-id:fake + Single-lit-var/imm32/next + +Two-float-args-in-regs: # (payload list var) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + Float-var-in-some-register/imm32 + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/next + +Two-args-float-reg-float-stack: # (payload list var) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + Float-var-in-some-register/imm32 + 0x11/imm32/alloc-id:fake + Single-float-var-in-mem/imm32/next + +Two-args-float-stack-float-reg: # (payload list var) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + Float-var-in-mem/imm32 + 0x11/imm32/alloc-id:fake + Single-float-var-in-some-register/imm32/next + +Single-int-var-in-some-register: # (payload list var) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + Int-var-in-some-register/imm32 + 0/imm32/next + 0/imm32/next + +Single-addr-var-in-some-register: # (payload list var) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + Addr-var-in-some-register/imm32 + 0/imm32/next + 0/imm32/next + +Single-byte-var-in-some-register: # (payload list var) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + Byte-var-in-some-register/imm32 + 0/imm32/next + 0/imm32/next + +Int-var-in-some-register: # (payload var) + 0x11/imm32/alloc-id:fake:payload + 0/imm32/name + 0/imm32/name + 0x11/imm32/alloc-id:fake + Type-int/imm32 + 1/imm32/some-block-depth + 0/imm32/no-stack-offset + 0x11/imm32/alloc-id:fake + Any-register/imm32 + +Any-register: # (payload array byte) + 0x11/imm32/alloc-id:fake:payload + 1/imm32/size + # data + 2a/asterisk + +Addr-var-in-some-register: # (payload var) + 0x11/imm32/alloc-id:fake:payload + 0/imm32/name + 0/imm32/name + 0x11/imm32/alloc-id:fake + Type-addr/imm32 + 1/imm32/some-block-depth + 0/imm32/no-stack-offset + 0x11/imm32/alloc-id:fake + Any-register/imm32 + +Byte-var-in-some-register: # (payload var) + 0x11/imm32/alloc-id:fake:payload + 0/imm32/name + 0/imm32/name + 0x11/imm32/alloc-id:fake + Type-byte/imm32 + 1/imm32/some-block-depth + 0/imm32/no-stack-offset + 0x11/imm32/alloc-id:fake + Any-register/imm32 + +Single-int-var-in-eax: # (payload list var) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + Int-var-in-eax/imm32 + 0/imm32/next + 0/imm32/next + +Int-var-in-eax: + 0x11/imm32/alloc-id:fake:payload + 0/imm32/name + 0/imm32/name + 0x11/imm32/alloc-id:fake + Type-int/imm32 + 1/imm32/some-block-depth + 0/imm32/no-stack-offset + 0x11/imm32/alloc-id:fake + $Mu-register-eax/imm32 # can't use Register-eax only to keep our buggy tools/treeshake.cc happy (TODO) + +Single-int-var-in-ecx: # (payload list var) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + Int-var-in-ecx/imm32 + 0/imm32/next + 0/imm32/next + +Int-var-in-ecx: + 0x11/imm32/alloc-id:fake:payload + 0/imm32/name + 0/imm32/name + 0x11/imm32/alloc-id:fake + Type-int/imm32 + 1/imm32/some-block-depth + 0/imm32/no-stack-offset + 0x11/imm32/alloc-id:fake + $Register-ecx/imm32/register + +Single-int-var-in-edx: # (payload list var) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + Int-var-in-edx/imm32 + 0/imm32/next + 0/imm32/next + +Int-var-in-edx: # (payload list var) + 0x11/imm32/alloc-id:fake:payload + 0/imm32/name + 0/imm32/name + 0x11/imm32/alloc-id:fake + Type-int/imm32 + 1/imm32/some-block-depth + 0/imm32/no-stack-offset + 0x11/imm32/alloc-id:fake + $Register-edx/imm32/register + +Single-int-var-in-ebx: # (payload list var) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + Int-var-in-ebx/imm32 + 0/imm32/next + 0/imm32/next + +Int-var-in-ebx: # (payload list var) + 0x11/imm32/alloc-id:fake:payload + 0/imm32/name + 0/imm32/name + 0x11/imm32/alloc-id:fake + Type-int/imm32 + 1/imm32/some-block-depth + 0/imm32/no-stack-offset + 0x11/imm32/alloc-id:fake + $Register-ebx/imm32/register + +Single-int-var-in-esi: # (payload list var) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + Int-var-in-esi/imm32 + 0/imm32/next + 0/imm32/next + +Int-var-in-esi: # (payload list var) + 0x11/imm32/alloc-id:fake:payload + 0/imm32/name + 0/imm32/name + 0x11/imm32/alloc-id:fake + Type-int/imm32 + 1/imm32/some-block-depth + 0/imm32/no-stack-offset + 0x11/imm32/alloc-id:fake + $Register-esi/imm32/register + +Single-int-var-in-edi: # (payload list var) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + Int-var-in-edi/imm32 + 0/imm32/next + 0/imm32/next + +Int-var-in-edi: # (payload list var) + 0x11/imm32/alloc-id:fake:payload + 0/imm32/name + 0/imm32/name + 0x11/imm32/alloc-id:fake + Type-int/imm32 + 1/imm32/some-block-depth + 0/imm32/no-stack-offset + 0x11/imm32/alloc-id:fake + $Register-edi/imm32/register + +Single-lit-var: # (payload list var) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + Lit-var/imm32 + 0/imm32/next + 0/imm32/next + +Lit-var: # (payload var) + 0x11/imm32/alloc-id:fake:payload + 0/imm32/name + 0/imm32/name + 0x11/imm32/alloc-id:fake + Type-literal/imm32 + 1/imm32/some-block-depth + 0/imm32/no-stack-offset + 0/imm32/no-register + 0/imm32/no-register + +Single-float-var-in-mem: # (payload list var) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + Float-var-in-mem/imm32 + 0/imm32/next + 0/imm32/next + +Float-var-in-mem: # (payload var) + 0x11/imm32/alloc-id:fake:payload + 0/imm32/name + 0/imm32/name + 0x11/imm32/alloc-id:fake + Type-float/imm32 + 1/imm32/some-block-depth + 1/imm32/some-stack-offset + 0/imm32/no-register + 0/imm32/no-register + +Single-float-var-in-some-register: # (payload list var) + 0x11/imm32/alloc-id:fake:payload + 0x11/imm32/alloc-id:fake + Float-var-in-some-register/imm32 + 0/imm32/next + 0/imm32/next + +Float-var-in-some-register: # (payload var) + 0x11/imm32/alloc-id:fake:payload + 0/imm32/name + 0/imm32/name + 0x11/imm32/alloc-id:fake + Type-float/imm32 + 1/imm32/some-block-depth + 0/imm32/no-stack-offset + 0x11/imm32/alloc-id:fake + Any-register/imm32 + +Type-int: # (payload type-tree) + 0x11/imm32/alloc-id:fake:payload + 1/imm32/is-atom + 1/imm32/value:int + 0/imm32/left:unused + 0/imm32/right:null + 0/imm32/right:null + +Type-literal: # (payload type-tree) + 0x11/imm32/alloc-id:fake:payload + 1/imm32/is-atom + 0/imm32/value:literal + 0/imm32/left:unused + 0/imm32/right:null + 0/imm32/right:null + +Type-addr: # (payload type-tree) + 0x11/imm32/alloc-id:fake:payload + 1/imm32/is-atom + 2/imm32/value:addr + 0/imm32/left:unused + 0/imm32/right:null + 0/imm32/right:null + +Type-byte: # (payload type-tree) + 0x11/imm32/alloc-id:fake:payload + 1/imm32/is-atom + 8/imm32/value:byte + 0/imm32/left:unused + 0/imm32/right:null + 0/imm32/right:null + +Type-float: # (payload type-tree) + 0x11/imm32/alloc-id:fake:payload + 1/imm32/is-atom + 0xf/imm32/value:float + 0/imm32/left:unused + 0/imm32/right:null + 0/imm32/right:null + +== code +emit-subx-primitive: # out: (addr buffered-file), stmt: (addr stmt), primitive: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + # ecx = primitive + 8b/-> *(ebp+0x10) 1/r32/ecx + # emit primitive name + (emit-indent *(ebp+8) *Curr-block-depth) + (lookup *(ecx+0x18) *(ecx+0x1c)) # Primitive-subx-name Primitive-subx-name => eax + (write-buffered *(ebp+8) %eax) + # emit rm32 if necessary + (emit-subx-rm32 *(ebp+8) *(ecx+0x20) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18)) # Primitive-subx-rm32 + # emit xm32 if necessary + (emit-subx-rm32 *(ebp+8) *(ecx+0x34) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18)) # Primitive-subx-xm32 + # emit r32 if necessary + (emit-subx-r32 *(ebp+8) *(ecx+0x24) *(ebp+0xc)) # Primitive-subx-r32 + # emit x32 if necessary + (emit-subx-x32 *(ebp+8) *(ecx+0x38) *(ebp+0xc)) # Primitive-subx-x32 + # emit imm32 if necessary + (emit-subx-imm32 *(ebp+8) *(ecx+0x28) *(ebp+0xc)) # Primitive-subx-imm32 + # emit imm8 if necessary + (emit-subx-imm8 *(ebp+8) *(ecx+0x2c) *(ebp+0xc)) # Primitive-subx-imm8 + # emit disp32 if necessary + (emit-subx-disp32 *(ebp+8) *(ecx+0x30) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18)) # Primitive-subx-disp32 + (write-buffered *(ebp+8) Newline) +$emit-subx-primitive:end: + # . restore registers + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +emit-subx-rm32: # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + # if (l == 0) return + 81 7/subop/compare *(ebp+0xc) 0/imm32 + 74/jump-if-= $emit-subx-rm32:end/disp8 + # var v/eax: (addr stmt-var) + (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18)) # => eax + (emit-subx-var-as-rm32 *(ebp+8) %eax) +$emit-subx-rm32:end: + # . restore registers + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +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) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # eax = l + 8b/-> *(ebp+0xc) 0/r32/eax + # ecx = stmt + 8b/-> *(ebp+8) 1/r32/ecx + # if (l == 1) return stmt->inouts + { + 3d/compare-eax-and 1/imm32 + 75/jump-if-!= break/disp8 +$get-stmt-operand-from-arg-location:1: + (lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax + eb/jump $get-stmt-operand-from-arg-location:end/disp8 + } + # if (l == 2) return stmt->inouts->next + { + 3d/compare-eax-and 2/imm32 + 75/jump-if-!= break/disp8 +$get-stmt-operand-from-arg-location:2: + (lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax + eb/jump $get-stmt-operand-from-arg-location:end/disp8 + } + # if (l == 3) return stmt->outputs + { + 3d/compare-eax-and 3/imm32 + 75/jump-if-!= break/disp8 +$get-stmt-operand-from-arg-location:3: + (lookup *(ecx+0x14) *(ecx+0x18)) # Stmt1-outputs Stmt1-outputs => eax + eb/jump $get-stmt-operand-from-arg-location:end/disp8 + } + # abort + e9/jump $get-stmt-operand-from-arg-location:abort/disp32 +$get-stmt-operand-from-arg-location:end: + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$get-stmt-operand-from-arg-location:abort: + # error("invalid arg-location " eax) + (write-buffered *(ebp+0x10) "invalid arg-location ") + (write-int32-hex-buffered *(ebp+0x10) %eax) + (write-buffered *(ebp+0x10) Newline) + (flush *(ebp+0x10)) + (stop *(ebp+0x14) 1) + # never gets here + +emit-subx-r32: # out: (addr buffered-file), l: arg-location, stmt: (addr stmt) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + # if (l == 0) return + 81 7/subop/compare *(ebp+0xc) 0/imm32 + 0f 84/jump-if-= $emit-subx-r32:end/disp32 + # var v/eax: (addr stmt-var) + (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # => eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax +#? (write-buffered Stderr "looking up ") +#? (write-buffered Stderr %eax) +#? (write-buffered Stderr Newline) +#? (flush Stderr) + (maybe-get Mu-registers %eax 0xc) # => eax: (addr register-index) + (write-buffered *(ebp+8) Space) + (write-int32-hex-buffered *(ebp+8) *eax) + (write-buffered *(ebp+8) "/r32") +$emit-subx-r32:end: + # . restore registers + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +emit-subx-x32: # out: (addr buffered-file), l: arg-location, stmt: (addr stmt) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + # if (l == 0) return + 81 7/subop/compare *(ebp+0xc) 0/imm32 + 0f 84/jump-if-= $emit-subx-x32:end/disp32 + # var v/eax: (addr stmt-var) + (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # => eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax +#? (write-buffered Stderr "looking up ") +#? (write-buffered Stderr %eax) +#? (write-buffered Stderr Newline) +#? (flush Stderr) + (maybe-get Mu-registers %eax 0xc) # => eax: (addr register-index) + (write-buffered *(ebp+8) Space) + (write-int32-hex-buffered *(ebp+8) *eax) + (write-buffered *(ebp+8) "/x32") +$emit-subx-x32:end: + # . restore registers + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +emit-subx-imm32: # out: (addr buffered-file), l: arg-location, stmt: (addr stmt) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + # if (l == 0) return + 81 7/subop/compare *(ebp+0xc) 0/imm32 + 0f 84/jump-if-= $emit-subx-imm32:end/disp32 + # var v/eax: (handle var) + (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # => eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+8) Space) + (write-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) "/imm32") +$emit-subx-imm32:end: + # . restore registers + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +emit-subx-imm8: # out: (addr buffered-file), l: arg-location, stmt: (addr stmt) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + # if (l == 0) return + 81 7/subop/compare *(ebp+0xc) 0/imm32 + 0f 84/jump-if-= $emit-subx-imm32:end/disp32 + # var v/eax: (handle var) + (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # => eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+8) Space) + (write-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) "/imm8") +$emit-subx-imm8:end: + # . restore registers + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +emit-subx-disp32: # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + # if (location == 0) return + 81 7/subop/compare *(ebp+0xc) 0/imm32 + 0f 84/jump-if-= $emit-subx-disp32:end/disp32 + # var v/eax: (addr stmt-var) + (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18)) # => eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+8) Space) + (write-buffered *(ebp+8) %eax) + # hack: if instruction operation starts with "break", emit ":break" + # var name/ecx: (addr array byte) = lookup(stmt->operation) + 8b/-> *(ebp+0x10) 0/r32/eax + (lookup *(eax+4) *(eax+8)) # Stmt1-operation Stmt1-operation => eax + 89/<- %ecx 0/r32/eax + { + (string-starts-with? %ecx "break") # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (write-buffered *(ebp+8) ":break") + } + # hack: if instruction operation starts with "loop", emit ":loop" + { + (string-starts-with? %ecx "loop") # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (write-buffered *(ebp+8) ":loop") + } + (write-buffered *(ebp+8) "/disp32") +$emit-subx-disp32:end: + # . restore registers + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +emit-call: # out: (addr buffered-file), stmt: (addr stmt) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + # + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "(") + # ecx = stmt + 8b/-> *(ebp+0xc) 1/r32/ecx + # - emit function name + (lookup *(ecx+4) *(ecx+8)) # Stmt1-operation Stmt1-operation => eax + (write-buffered *(ebp+8) %eax) + # - emit arguments + # var curr/eax: (addr stmt-var) = lookup(stmt->inouts) + (lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax + { + # if (curr == null) break + 3d/compare-eax-and 0/imm32 + 74/jump-if-= break/disp8 + # + (emit-subx-call-operand *(ebp+8) %eax) + # curr = lookup(curr->next) + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax + eb/jump loop/disp8 + } + # + (write-buffered *(ebp+8) ")\n") +$emit-call:end: + # . restore registers + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +emit-subx-call-operand: # out: (addr buffered-file), s: (addr stmt-var) + # shares code with emit-subx-var-as-rm32 + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 56/push-esi + # ecx = s + 8b/-> *(ebp+0xc) 1/r32/ecx + # var operand/esi: (addr var) = lookup(s->value) + (lookup *ecx *(ecx+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %esi 0/r32/eax + # if (operand->register && !s->is-deref?) emit "%__" + { +$emit-subx-call-operand:check-for-register-direct: + 81 7/subop/compare *(esi+0x18) 0/imm32 # Var-register + 74/jump-if-= break/disp8 + 81 7/subop/compare *(ecx+0x10) 0/imm32/false # Stmt-var-is-deref + 75/jump-if-!= break/disp8 +$emit-subx-call-operand:register-direct: + (write-buffered *(ebp+8) " %") + (lookup *(esi+0x18) *(esi+0x1c)) # Var-register Var-register => eax + (write-buffered *(ebp+8) %eax) + e9/jump $emit-subx-call-operand:end/disp32 + } + # else if (operand->register && s->is-deref?) emit "*__" + { +$emit-subx-call-operand:check-for-register-indirect: + 81 7/subop/compare *(esi+0x18) 0/imm32 # Var-register + 74/jump-if-= break/disp8 + 81 7/subop/compare *(ecx+0x10) 0/imm32/false # Stmt-var-is-deref + 74/jump-if-= break/disp8 +$emit-subx-call-operand:register-indirect: + (emit-subx-call-operand-register-indirect *(ebp+8) %esi) + e9/jump $emit-subx-call-operand:end/disp32 + } + # else if (operand->stack-offset) emit "*(ebp+__)" + { + 81 7/subop/compare *(esi+0x14) 0/imm32 # Var-offset + 74/jump-if-= break/disp8 +$emit-subx-call-operand:stack: + (emit-subx-call-operand-stack *(ebp+8) %esi) + e9/jump $emit-subx-call-operand:end/disp32 + } + # else if (operand->type == literal) emit "__" + { + (lookup *(esi+8) *(esi+0xc)) # Var-type Var-type => eax + 81 7/subop/compare *(eax+4) 0/imm32 # Type-tree-value + 75/jump-if-!= break/disp8 +$emit-subx-call-operand:literal: + (write-buffered *(ebp+8) Space) + (lookup *esi *(esi+4)) # Var-name Var-name => eax + (write-buffered *(ebp+8) %eax) + e9/jump $emit-subx-call-operand:end/disp32 + } + # else if (operand->type == literal-string) emit "__" + { + (lookup *(esi+8) *(esi+0xc)) # Var-type Var-type => eax + 81 7/subop/compare *(eax+4) 0x10/imm32 # Type-tree-value + 75/jump-if-!= break/disp8 +$emit-subx-call-operand:literal-string: + (write-buffered *(ebp+8) Space) + (lookup *esi *(esi+4)) # Var-name Var-name => eax + (write-buffered *(ebp+8) %eax) + } +$emit-subx-call-operand:end: + # . restore registers + 5e/pop-to-esi + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +emit-subx-call-operand-register-indirect: # out: (addr buffered-file), v: (addr var) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 56/push-esi + # esi = v + 8b/-> *(ebp+0xc) 6/r32/esi + # var size/ecx: int = size-of-deref(v) + (size-of-deref %esi) # => eax + 89/<- %ecx 0/r32/eax + # var reg-name/esi: (addr array byte) = lookup(v->register) + (lookup *(esi+0x18) *(esi+0x1c)) # Var-register Var-register => eax + 89/<- %esi 0/r32/eax + # TODO: assert size is a multiple of 4 + # var i/eax: int = 0 + b8/copy-to-eax 0/imm32 + { +$emit-subx-call-operand-register-indirect:loop: + # if (i >= size) break + 39/compare %eax 1/r32/ecx + 7d/jump-if->= break/disp8 + # emit " *(" v->register "+" i ")" + (write-buffered *(ebp+8) " *(") + (write-buffered *(ebp+8) %esi) + (write-buffered *(ebp+8) "+") + (write-int32-hex-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) ")") + # i += 4 + 05/add-to-eax 4/imm32 + # + eb/jump loop/disp8 + } +$emit-subx-call-operand-register-indirect:end: + # . restore registers + 5e/pop-to-esi + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +emit-subx-call-operand-stack: # out: (addr buffered-file), v: (addr var) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 56/push-esi + # esi = v + 8b/-> *(ebp+0xc) 6/r32/esi + # var curr/ecx: int = v->offset + 8b/-> *(esi+0x14) 1/r32/ecx # Var-offset + # var max/eax: int = v->offset + size-of(v) + (size-of %esi) # => eax + # TODO: assert size is a multiple of 4 + 01/add-to %eax 1/r32/ecx + { +$emit-subx-call-operand-stack:loop: + # if (curr >= max) break + 39/compare %ecx 0/r32/eax + 7d/jump-if->= break/disp8 + # emit " *(ebp+" curr ")" + (write-buffered *(ebp+8) " *(ebp+") + (write-int32-hex-buffered *(ebp+8) %ecx) + (write-buffered *(ebp+8) ")") + # i += 4 + 81 0/subop/add %ecx 4/imm32 + # + eb/jump loop/disp8 + } +$emit-subx-call-operand-stack:end: + # . restore registers + 5e/pop-to-esi + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +emit-subx-var-as-rm32: # out: (addr buffered-file), s: (addr stmt-var) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 56/push-esi + # ecx = s + 8b/-> *(ebp+0xc) 1/r32/ecx + # var operand/esi: (addr var) = lookup(s->value) + (lookup *ecx *(ecx+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %esi 0/r32/eax + # if (operand->register && s->is-deref?) emit "*__" + { +$emit-subx-var-as-rm32:check-for-register-indirect: + 81 7/subop/compare *(esi+0x18) 0/imm32 # Var-register + 74/jump-if-= break/disp8 + 81 7/subop/compare *(ecx+0x10) 0/imm32/false # Stmt-var-is-deref + 74/jump-if-= break/disp8 +$emit-subx-var-as-rm32:register-indirect: + (write-buffered *(ebp+8) " *") + (lookup *(esi+0x18) *(esi+0x1c)) # Var-register Var-register => eax + (write-buffered *(ebp+8) %eax) + e9/jump $emit-subx-var-as-rm32:end/disp32 + } + # if (operand->register && !s->is-deref?) emit "%__" + { +$emit-subx-var-as-rm32:check-for-register-direct: + 81 7/subop/compare *(esi+0x18) 0/imm32 # Var-register + 74/jump-if-= break/disp8 + 81 7/subop/compare *(ecx+0x10) 0/imm32/false # Stmt-var-is-deref + 75/jump-if-!= break/disp8 +$emit-subx-var-as-rm32:register-direct: + (write-buffered *(ebp+8) " %") + (lookup *(esi+0x18) *(esi+0x1c)) # Var-register Var-register => eax + (write-buffered *(ebp+8) %eax) + e9/jump $emit-subx-var-as-rm32:end/disp32 + } + # else if (operand->stack-offset) emit "*(ebp+__)" + { + 81 7/subop/compare *(esi+0x14) 0/imm32 # Var-offset + 74/jump-if-= break/disp8 +$emit-subx-var-as-rm32:stack: + (write-buffered *(ebp+8) Space) + (write-buffered *(ebp+8) "*(ebp+") + (write-int32-hex-buffered *(ebp+8) *(esi+0x14)) # Var-offset + (write-buffered *(ebp+8) ")") + } +$emit-subx-var-as-rm32:end: + # . restore registers + 5e/pop-to-esi + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +find-matching-primitive: # primitives: (addr primitive), stmt: (addr stmt) -> result/eax: (addr primitive) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # var curr/ecx: (addr primitive) = primitives + 8b/-> *(ebp+8) 1/r32/ecx + { +$find-matching-primitive:loop: + # if (curr == null) break + 81 7/subop/compare %ecx 0/imm32 + 74/jump-if-= break/disp8 + # if match(curr, stmt) return curr + { + (mu-stmt-matches-primitive? *(ebp+0xc) %ecx) # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + 89/<- %eax 1/r32/ecx + eb/jump $find-matching-primitive:end/disp8 + } +$find-matching-primitive:next-primitive: + # curr = curr->next + (lookup *(ecx+0x3c) *(ecx+0x40)) # Primitive-next Primitive-next => eax + 89/<- %ecx 0/r32/eax + # + e9/jump loop/disp32 + } + # return null + b8/copy-to-eax 0/imm32 +$find-matching-primitive:end: + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +mu-stmt-matches-primitive?: # stmt: (addr stmt), primitive: (addr primitive) -> result/eax: boolean + # A mu stmt matches a primitive if the name matches, all the inout vars + # match, and all the output vars match. + # Vars match if types match and registers match. + # In addition, a stmt output matches a primitive's output if types match + # and the primitive has a wildcard register. + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + 57/push-edi + # ecx = stmt + 8b/-> *(ebp+8) 1/r32/ecx + # edx = primitive + 8b/-> *(ebp+0xc) 2/r32/edx + { +$mu-stmt-matches-primitive?:check-name: + # if (primitive->name != stmt->operation) return false + # . var esi: (addr array byte) = lookup(stmt->operation) + (lookup *(ecx+4) *(ecx+8)) # Stmt1-operation Stmt1-operation => eax + 89/<- %esi 0/r32/eax + # . var edi: (addr array byte) = lookup(primitive->name) + (lookup *edx *(edx+4)) # Primitive-name Primitive-name => eax +#? (write-buffered Stderr %eax) +#? (write-buffered Stderr Newline) +#? (flush Stderr) + 89/<- %edi 0/r32/eax + (string-equal? %esi %edi) # => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 + b8/copy-to-eax 0/imm32 + e9/jump $mu-stmt-matches-primitive?:end/disp32 + } + # var curr/esi: (addr stmt-var) = lookup(stmt->inouts) + (lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax + 89/<- %esi 0/r32/eax + # var curr2/edi: (addr list var) = lookup(primitive->inouts) + (lookup *(edx+8) *(edx+0xc)) # Primitive-inouts Primitive-inouts => eax + 89/<- %edi 0/r32/eax + { +$mu-stmt-matches-primitive?:inouts-loop: + # if (curr == 0 && curr2 == 0) move on to check outputs + { +$mu-stmt-matches-primitive?:check-both-inouts-null: + 81 7/subop/compare %esi 0/imm32 + 75/jump-if-!= break/disp8 +$mu-stmt-matches-primitive?:stmt-inout-null: + 81 7/subop/compare %edi 0/imm32 + 0f 84/jump-if-= $mu-stmt-matches-primitive?:check-outputs/disp32 +$mu-stmt-matches-primitive?:stmt-inout-null-and-prim-inout-not-null: + # return false + b8/copy-to-eax 0/imm32/false + e9/jump $mu-stmt-matches-primitive?:end/disp32 + } + # if (curr2 == 0) return false + { +$mu-stmt-matches-primitive?:check-prim-inout-null: + 81 7/subop/compare %edi 0/imm32 + 75/jump-if-!= break/disp8 +$mu-stmt-matches-primitive?:prim-inout-null: + b8/copy-to-eax 0/imm32/false + e9/jump $mu-stmt-matches-primitive?:end/disp32 + } + # if (curr != curr2) return false + { +$mu-stmt-matches-primitive?:check-inouts-match: + (lookup *edi *(edi+4)) # List-value List-value => eax + (operand-matches-primitive? %esi %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 +$mu-stmt-matches-primitive?:inouts-match: + b8/copy-to-eax 0/imm32/false + e9/jump $mu-stmt-matches-primitive?:end/disp32 + } +$mu-stmt-matches-primitive?:next-inout: + # curr = lookup(curr->next) + (lookup *(esi+8) *(esi+0xc)) # Stmt-var-next Stmt-var-next => eax + 89/<- %esi 0/r32/eax + # curr2 = lookup(curr2->next) + (lookup *(edi+8) *(edi+0xc)) # List-next List-next => eax + 89/<- %edi 0/r32/eax + # + e9/jump loop/disp32 + } +$mu-stmt-matches-primitive?:check-outputs: + # var curr/esi: (addr stmt-var) = lookup(stmt->outputs) + (lookup *(ecx+0x14) *(ecx+0x18)) # Stmt1-outputs Stmt1-outputs => eax + 89/<- %esi 0/r32/eax + # var curr2/edi: (addr list var) = lookup(primitive->outputs) + (lookup *(edx+0x10) *(edx+0x14)) # Primitive-outputs Primitive-outputs => eax + 89/<- %edi 0/r32/eax + { +$mu-stmt-matches-primitive?:outputs-loop: + # if (curr == 0) return (curr2 == 0) + { +$mu-stmt-matches-primitive?:check-both-outputs-null: + 81 7/subop/compare %esi 0/imm32 + 75/jump-if-!= break/disp8 + { +$mu-stmt-matches-primitive?:stmt-output-null: + 81 7/subop/compare %edi 0/imm32 + 75/jump-if-!= break/disp8 +$mu-stmt-matches-primitive?:both-outputs-null: + # return true + b8/copy-to-eax 1/imm32 + e9/jump $mu-stmt-matches-primitive?:end/disp32 + } +$mu-stmt-matches-primitive?:stmt-output-null-and-prim-output-not-null: + # return false + b8/copy-to-eax 0/imm32 + e9/jump $mu-stmt-matches-primitive?:end/disp32 + } + # if (curr2 == 0) return false + { +$mu-stmt-matches-primitive?:check-prim-output-null: + 81 7/subop/compare %edi 0/imm32 + 75/jump-if-!= break/disp8 +$mu-stmt-matches-primitive?:prim-output-is-null: + b8/copy-to-eax 0/imm32 + e9/jump $mu-stmt-matches-primitive?:end/disp32 + } + # if (curr != curr2) return false + { +$mu-stmt-matches-primitive?:check-outputs-match: + (lookup *edi *(edi+4)) # List-value List-value => eax + (operand-matches-primitive? %esi %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 +$mu-stmt-matches-primitive?:outputs-match: + b8/copy-to-eax 0/imm32 + e9/jump $mu-stmt-matches-primitive?:end/disp32 + } +$mu-stmt-matches-primitive?:next-output: + # curr = lookup(curr->next) + (lookup *(esi+8) *(esi+0xc)) # Stmt-var-next Stmt-var-next => eax + 89/<- %esi 0/r32/eax + # curr2 = lookup(curr2->next) + (lookup *(edi+8) *(edi+0xc)) # List-next List-next => eax + 89/<- %edi 0/r32/eax + # + e9/jump loop/disp32 + } +$mu-stmt-matches-primitive?:return-true: + b8/copy-to-eax 1/imm32 +$mu-stmt-matches-primitive?:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +operand-matches-primitive?: # s: (addr stmt-var), prim-var: (addr var) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + 52/push-edx + 53/push-ebx + 56/push-esi + 57/push-edi + # ecx = s + 8b/-> *(ebp+8) 1/r32/ecx + # var var/esi: (addr var) = lookup(s->value) + (lookup *ecx *(ecx+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %esi 0/r32/eax + # edi = prim-var + 8b/-> *(ebp+0xc) 7/r32/edi +$operand-matches-primitive?:check-type: + # if !category-match?(var->type, prim-var->type) return false + # . var vtype/ebx: (addr type-tree) = lookup(var->type) + (lookup *(esi+8) *(esi+0xc)) # Var-type Var-type => eax + 89/<- %ebx 0/r32/eax + # . if s is deref, vtype = vtype->right + { + 81 7/subop/compare *(ecx+0x10) 0/imm32/false # Stmt-var-is-deref + 74/jump-if-= break/disp8 +$operand-matches-primitive?:is-deref: + # . var t/eax: (addr type) + (lookup *(ebx+0xc) *(ebx+0x10)) # Type-tree-right Type-tree-right => eax + # . if !t->is-atom? t = t->left + 81 7/subop/compare *eax 0/imm32/false + { + 75/jump-if-!= break/disp8 + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } + # . + 89/<- %ebx 0/r32/eax + } + # . var ptype/eax: (addr type-tree) = lookup(prim-var->type) + (lookup *(edi+8) *(edi+0xc)) # Var-type Var-type => eax + (subx-type-category-match? %ebx %eax) # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $operand-matches-primitive?:return-false/disp32 + { +$operand-matches-primitive?:check-register: + # if prim-var is in memory and var is in register but dereference, match + { + 81 7/subop/compare *(edi+0x18) 0/imm32 # Var-register + 0f 85/jump-if-!= break/disp32 + 81 7/subop/compare *(esi+0x18) 0/imm32 # Var-register + 74/jump-if-= break/disp8 + 81 7/subop/compare *(ecx+0x10) 0/imm32/false # Stmt-var-is-deref + 74/jump-if-= break/disp8 +$operand-matches-primitive?:var-deref-match: + e9/jump $operand-matches-primitive?:return-true/disp32 + } + # if prim-var is in register and var is in register but dereference, no match + { + 81 7/subop/compare *(edi+0x18) 0/imm32 # Var-register + 0f 84/jump-if-= break/disp32 + 81 7/subop/compare *(esi+0x18) 0/imm32 # Var-register + 0f 84/jump-if-= break/disp32 + 81 7/subop/compare *(ecx+0x10) 0/imm32/false # Stmt-var-is-deref + 74/jump-if-= break/disp8 +$operand-matches-primitive?:var-deref-no-match: + e9/jump $operand-matches-primitive?:return-false/disp32 + } + # return false if var->register doesn't match prim-var->register + { + # if register addresses are equal, it's a match + # var vreg/ebx: (addr array byte) = lookup(var->register) + (lookup *(esi+0x18) *(esi+0x1c)) # Var-register Var-register => eax + 89/<- %ebx 0/r32/eax + # var preg/ecx: (addr array byte) = lookup(prim-var->register) + (lookup *(edi+0x18) *(edi+0x1c)) # Var-register Var-register => eax + 89/<- %ecx 0/r32/eax + # if (vreg == preg) break + 39/compare %ecx 3/r32/ebx + 74/jump-if-= break/disp8 +$operand-matches-primitive?:var-register-no-match: + # if either address is 0, return false + 81 7/subop/compare %ebx 0/imm32 + 74/jump-if-= $operand-matches-primitive?:return-false/disp8 + 81 7/subop/compare %ecx 0/imm32 + 74/jump-if-= $operand-matches-primitive?:return-false/disp8 + # if prim-var->register is wildcard, it's a match + (string-equal? %ecx "*") # Any-register => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 +$operand-matches-primitive?:wildcard-no-match: + # if string contents aren't equal, return false + (string-equal? %ecx %ebx) # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= $operand-matches-primitive?:return-false/disp8 + } + } +$operand-matches-primitive?:return-true: + b8/copy-to-eax 1/imm32/true + eb/jump $operand-matches-primitive?:end/disp8 +$operand-matches-primitive?:return-false: + b8/copy-to-eax 0/imm32/false +$operand-matches-primitive?:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +find-matching-function: # functions: (addr function), stmt: (addr stmt) -> result/eax: (addr function) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # var curr/ecx: (handle function) = functions + 8b/-> *(ebp+8) 1/r32/ecx + { + # if (curr == null) break + 81 7/subop/compare %ecx 0/imm32 + 74/jump-if-= break/disp8 +#? (write-buffered Stderr "iter\n") +#? (flush Stderr) + # if match(stmt, curr) return curr + { + (mu-stmt-matches-function? *(ebp+0xc) %ecx) # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + 89/<- %eax 1/r32/ecx + eb/jump $find-matching-function:end/disp8 + } + # curr = curr->next + (lookup *(ecx+0x20) *(ecx+0x24)) # Function-next Function-next => eax + 89/<- %ecx 0/r32/eax + # + eb/jump loop/disp8 + } + # return null + b8/copy-to-eax 0/imm32 +$find-matching-function:end: + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# Just compare names; user-defined functions don't support overloading yet. +mu-stmt-matches-function?: # stmt: (addr stmt1), function: (addr function) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # return function->name == stmt->operation + # ecx = lookup(stmt->operation) + 8b/-> *(ebp+8) 0/r32/eax + (lookup *(eax+4) *(eax+8)) # Stmt1-operation Stmt1-operation => eax + 89/<- %ecx 0/r32/eax + # eax = lookup(function->name) + 8b/-> *(ebp+0xc) 0/r32/eax + (lookup *eax *(eax+4)) # Function-name Function-name => eax + (string-equal? %eax %ecx) # => eax +$mu-stmt-matches-function?:end: + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# Type-checking happens elsewhere. This method is for selecting between +# primitives. +subx-type-category-match?: # a: (addr type-tree), b: (addr type-tree) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # var cata/ecx: int = type-category(a) + (type-category *(ebp+8)) # => eax + 89/<- %ecx 0/r32/eax + # var catb/eax: int = type-category(b) + (type-category *(ebp+0xc)) # => eax + # return cata == catb + 39/compare %eax 1/r32/ecx + 0f 94/set-byte-if-= %al + 81 4/subop/and %eax 0xff/imm32 +$subx-type-category-match?:end: + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +type-category: # a: (addr type-tree) -> result/eax: int + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # var lit?/ecx: boolean = is-literal-type?(a) + (is-simple-mu-type? *(ebp+8) 0) # literal => eax + 89/<- %ecx 0/r32/eax + # var float?/eax: int = is-float?(a) + (is-simple-mu-type? *(ebp+8) 0xf) # => eax + # set bits for lit? and float? + c1/shift 4/subop/left %ecx 1/imm8 + 09/or %eax 1/r32/ecx +$type-category:end: + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +is-simple-mu-type?: # a: (addr type-tree), n: type-id -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # ecx = n + 8b/-> *(ebp+0xc) 1/r32/ecx + # return (a->value == n) + 8b/-> *(ebp+8) 0/r32/eax + 39/compare *(eax+4) 1/r32/ecx # Type-tree-value + 0f 94/set-byte-if-= %al + 81 4/subop/and %eax 0xff/imm32 +$is-simple-mu-type?:end: + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +is-mu-addr-type?: # a: (addr type-tree) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # eax = a + 8b/-> *(ebp+8) 0/r32/eax + # if (!a->is-atom?) a = a->left + 81 7/subop/compare *eax 0/imm32/false # Type-tree-is-atom + { + 75/jump-if-!= break/disp8 + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } + # return (a->value == addr) + 81 7/subop/compare *(eax+4) 2/imm32/addr # Type-tree-value + 0f 94/set-byte-if-= %al + 81 4/subop/and %eax 0xff/imm32 +$is-mu-addr-type?:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +is-mu-array-type?: # a: (addr type-tree) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # eax = a + 8b/-> *(ebp+8) 0/r32/eax + # if (!a->is-atom?) a = a->left + 81 7/subop/compare *eax 0/imm32/false # Type-tree-is-atom + { + 75/jump-if-!= break/disp8 + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } + # return (a->value == array) + 81 7/subop/compare *(eax+4) 3/imm32/array # Type-tree-value + 0f 94/set-byte-if-= %al + 81 4/subop/and %eax 0xff/imm32 +$is-mu-array-type?:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +is-mu-string-type?: # a: (addr type-tree) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 56/push-esi + # esi = a + 8b/-> *(ebp+8) 6/r32/esi + # if (a->is-atom?) return false + 81 7/subop/compare *esi 0/imm32/false # Type-tree-is-atom + 0f 85/jump-if-!= $is-mu-string-type?:return-false/disp32 + # if a is not an addr, return false + (is-mu-addr-type? %esi) # => eax + 3d/compare-eax-with 0/imm32/false + 0f 84/jump-if-= $is-mu-string-type?:end/disp32 # eax changes var + # if a is not an array, return false + (lookup *(esi+0xc) *(esi+0x10)) # Type-tree-right Type-tree-right => eax + (is-mu-array-type? %eax) # => eax + 3d/compare-eax-with 0/imm32/false + 74/jump-if-= $is-mu-string-type?:end/disp8 # eax changes var + # var p/eax: (addr type-tree) = payload of a + (lookup *(esi+0xc) *(esi+0x10)) # Type-tree-right Type-tree-right => eax + (lookup *(eax+0xc) *(eax+0x10)) # Type-tree-right Type-tree-right => eax + # if p is an atom, return false + 81 7/subop/compare *eax 0/imm32/false # Type-tree-is-atom + 75/jump-if-!= $is-mu-string-type?:return-false/disp8 + # return (p == byte) + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 8) # byte => eax + eb/jump $is-mu-string-type?:end/disp8 +$is-mu-string-type?:return-false: + b8/copy-to-eax 0/imm32/false +$is-mu-string-type?:end: + # . restore registers + 5e/pop-to-esi + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +is-mu-stream-type?: # a: (addr type-tree) -> result/eax: boolean + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # eax = a + 8b/-> *(ebp+8) 0/r32/eax + # if (!a->is-atom?) a = a->left + 81 7/subop/compare *eax 0/imm32/false # Type-tree-is-atom + { + 75/jump-if-!= break/disp8 + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + } + # return (a->value == stream) + 81 7/subop/compare *(eax+4) 0xb/imm32/stream # Type-tree-value + 0f 94/set-byte-if-= %al + 81 4/subop/and %eax 0xff/imm32 +$is-mu-stream-type?:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-emit-subx-stmt-primitive: + # Primitive operation on a variable on the stack. + # increment foo + # => + # ff 0/subop/increment *(ebp-8) + # + # There's a variable on the var stack as follows: + # name: 'foo' + # type: int + # stack-offset: -8 + # + # There's a primitive with this info: + # name: 'increment' + # inouts: int/mem + # value: 'ff 0/subop/increment' + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) + # simulate allocated payloads starting with an initial fake alloc-id (0x11) +$test-emit-subx-stmt-primitive:initialize-type: + # var type/ecx: (payload type-tree) = int + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 1/imm32/value:int + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-emit-subx-stmt-primitive:initialize-var: + # var var-foo/ecx: (payload var) = var(type) + 68/push 0/imm32/no-register + 68/push 0/imm32/no-register + 68/push -8/imm32/stack-offset + 68/push 1/imm32/block-depth + 51/push-ecx/type + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-emit-subx-stmt-primitive:initialize-var-name: + # var-foo->name = "foo" + 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "foo" %eax) +$test-emit-subx-stmt-primitive:initialize-stmt-var: + # var operand/ebx: (payload stmt-var) = stmt-var(var-foo) + 68/push 0/imm32/is-deref:false + 68/push 0/imm32/next + 68/push 0/imm32/next + 51/push-ecx/var-foo + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ebx 4/r32/esp +$test-emit-subx-stmt-primitive:initialize-stmt: + # var stmt/esi: (addr statement) + 68/push 0/imm32/no-outputs + 68/push 0/imm32/no-outputs + 53/push-ebx/inouts + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/operation + 68/push 0/imm32/operation + 68/push 1/imm32/tag + 89/<- %esi 4/r32/esp +$test-emit-subx-stmt-primitive:initialize-stmt-operation: + # stmt->operation = "increment" + 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation + (copy-array Heap "increment" %eax) +$test-emit-subx-stmt-primitive:initialize-primitive: + # var primitives/ebx: (addr primitive) + 68/push 0/imm32/next + 68/push 0/imm32/next + 68/push 0/imm32/no-x32 + 68/push 0/imm32/no-xm32 + 68/push 0/imm32/no-disp32 + 68/push 0/imm32/no-imm8 + 68/push 0/imm32/no-imm32 + 68/push 0/imm32/no-r32 + 68/push 1/imm32/rm32-is-first-inout + 68/push 0/imm32/subx-name + 68/push 0/imm32/subx-name + 68/push 0/imm32/no-outputs + 68/push 0/imm32/no-outputs + 53/push-ebx/inouts # hack: reuse stmt-var from call stmt as (list var) in function declaration + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 89/<- %ebx 4/r32/esp +$test-emit-subx-stmt-primitive:initialize-primitive-name: + # primitives->name = "increment" + (copy-array Heap "increment" %ebx) # Primitive-name +$test-emit-subx-stmt-primitive:initialize-primitive-subx-name: + # primitives->subx-name = "ff 0/subop/increment" + 8d/copy-address *(ebx+0x18) 0/r32/eax # Primitive-subx-name + (copy-array Heap "ff 0/subop/increment" %eax) + # convert + c7 0/subop/copy *Curr-block-depth 0/imm32 + (emit-subx-stmt _test-output-buffered-file %esi %ebx 0 Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-stmt-primitive") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-emit-subx-stmt-primitive-register: + # Primitive operation on a variable in a register. + # foo <- increment + # => + # ff 0/subop/increment %eax # sub-optimal, but should suffice + # + # There's a variable on the var stack as follows: + # name: 'foo' + # type: int + # register: 'eax' + # + # There's a primitive with this info: + # name: 'increment' + # out: int/reg + # value: 'ff 0/subop/increment' + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) +$test-emit-subx-stmt-primitive-register:initialize-type: + # var type/ecx: (payload type-tree) = int + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 1/imm32/value:int + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-emit-subx-stmt-primitive-register:initialize-var: + # var var-foo/ecx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + 51/push-ecx + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-emit-subx-stmt-primitive-register:initialize-var-name: + # var-foo->name = "foo" + 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "foo" %eax) +$test-emit-subx-stmt-primitive-register:initialize-var-register: + # var-foo->register = "eax" + 8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4 + (copy-array Heap "eax" %eax) +$test-emit-subx-stmt-primitive-register:initialize-stmt-var: + # var operand/ebx: (payload stmt-var) + 68/push 0/imm32/is-deref:false + 68/push 0/imm32/next + 68/push 0/imm32/next + 51/push-ecx/var-foo + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ebx 4/r32/esp +$test-emit-subx-stmt-primitive-register:initialize-stmt: + # var stmt/esi: (addr statement) + 53/push-ebx/outputs + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/no-inouts + 68/push 0/imm32/no-inouts + 68/push 0/imm32/operation + 68/push 0/imm32/operation + 68/push 1/imm32 + 89/<- %esi 4/r32/esp +$test-emit-subx-stmt-primitive-register:initialize-stmt-operation: + # stmt->operation = "increment" + 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation + (copy-array Heap "increment" %eax) +$test-emit-subx-stmt-primitive-register:initialize-formal-var: + # var formal-var/ebx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + ff 6/subop/push *(ecx+0x10) # Var-type + payload alloc id + handle alloc id + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ebx 4/r32/esp +$test-emit-subx-stmt-primitive-register:initialize-formal-var-name: + # formal-var->name = "dummy" + 8d/copy-address *(ebx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "dummy" %eax) +$test-emit-subx-stmt-primitive-register:initialize-formal-register: + # formal-var->register = "*" + 8d/copy-address *(ebx+0x1c) 0/r32/eax # Var-register + 4 + (copy-array Heap "*" %eax) # Any-register +$test-emit-subx-stmt-primitive-register:initialize-var-list: + # var formal-outputs/ebx: (payload list var) + 68/push 0/imm32/next + 68/push 0/imm32/next + 53/push-ebx/formal-var + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ebx 4/r32/esp +$test-emit-subx-stmt-primitive-register:initialize-primitive: + # var primitives/ebx: (addr primitive) + 68/push 0/imm32/next + 68/push 0/imm32/next + 68/push 0/imm32/no-x32 + 68/push 0/imm32/no-xm32 + 68/push 0/imm32/no-disp32 + 68/push 0/imm32/no-imm8 + 68/push 0/imm32/no-imm32 + 68/push 0/imm32/no-r32 + 68/push 3/imm32/rm32-is-first-output + 68/push 0/imm32/subx-name + 68/push 0/imm32/subx-name + 53/push-ebx/outputs + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/no-inouts + 68/push 0/imm32/no-inouts + 68/push 0/imm32/name + 68/push 0/imm32/name + 89/<- %ebx 4/r32/esp +$test-emit-subx-stmt-primitive-register:initialize-primitive-name: + # primitives->name = "increment" + (copy-array Heap "increment" %ebx) # Primitive-name +$test-emit-subx-stmt-primitive-register:initialize-primitive-subx-name: + # primitives->subx-name = "ff 0/subop/increment" + 8d/copy-address *(ebx+0x18) 0/r32/eax # Primitive-subx-name + (copy-array Heap "ff 0/subop/increment" %eax) + # convert + c7 0/subop/copy *Curr-block-depth 0/imm32 + (emit-subx-stmt _test-output-buffered-file %esi %ebx 0 Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-primitive-register") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-emit-subx-stmt-select-primitive: + # Select the right primitive between overloads. + # foo <- increment + # => + # ff 0/subop/increment %eax # sub-optimal, but should suffice + # + # There's a variable on the var stack as follows: + # name: 'foo' + # type: int + # register: 'eax' + # + # There's two primitives, as follows: + # - name: 'increment' + # out: int/reg + # value: 'ff 0/subop/increment' + # - name: 'increment' + # inout: int/mem + # value: 'ff 0/subop/increment' + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) +$test-emit-subx-stmt-select-primitive:initialize-type: + # var type/ecx: (payload type-tree) = int + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 1/imm32/value:int + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-emit-subx-stmt-select-primitive:initialize-var: + # var var-foo/ecx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + 51/push-ecx + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-emit-subx-stmt-select-primitive:initialize-var-name: + # var-foo->name = "foo" + 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "foo" %eax) +$test-emit-subx-stmt-select-primitive:initialize-var-register: + # var-foo->register = "eax" + 8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4 + (copy-array Heap "eax" %eax) +$test-emit-subx-stmt-select-primitive:initialize-stmt-var: + # var operand/ebx: (payload stmt-var) + 68/push 0/imm32/is-deref:false + 68/push 0/imm32/next + 68/push 0/imm32/next + 51/push-ecx/var-foo + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ebx 4/r32/esp +$test-emit-subx-stmt-select-primitive:initialize-stmt: + # var stmt/esi: (addr statement) + 53/push-ebx/outputs + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/no-inouts + 68/push 0/imm32/no-inouts + 68/push 0/imm32/operation + 68/push 0/imm32/operation + 68/push 1/imm32 + 89/<- %esi 4/r32/esp +$test-emit-subx-stmt-select-primitive:initialize-stmt-operation: + # stmt->operation = "increment" + 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation + (copy-array Heap "increment" %eax) +$test-emit-subx-stmt-select-primitive:initialize-formal-var: + # var formal-var/ebx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + ff 6/subop/push *(ecx+0x10) # Var-type + payload alloc id + handle alloc id + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ebx 4/r32/esp +$test-emit-subx-stmt-select-primitive:initialize-formal-var-name: + # formal-var->name = "dummy" + 8d/copy-address *(ebx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "dummy" %eax) +$test-emit-subx-stmt-select-primitive:initialize-formal-register: + # formal-var->register = "*" + 8d/copy-address *(ebx+0x1c) 0/r32/eax # Var-register + 4 + (copy-array Heap "*" %eax) # Any-register +$test-emit-subx-stmt-select-primitive:initialize-var-list: + # var formal-outputs/ebx: (payload list var) + 68/push 0/imm32/next + 68/push 0/imm32/next + 53/push-ebx/formal-var + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ebx 4/r32/esp +$test-emit-subx-stmt-select-primitive:initialize-primitive2: + # var primitive2/edi: (payload primitive) + 68/push 0/imm32/next + 68/push 0/imm32/next + 68/push 0/imm32/no-x32 + 68/push 0/imm32/no-xm32 + 68/push 0/imm32/no-disp32 + 68/push 0/imm32/no-imm8 + 68/push 0/imm32/no-imm32 + 68/push 0/imm32/no-r32 + 68/push 3/imm32/rm32-is-first-output + 68/push 0/imm32/subx-name + 68/push 0/imm32/subx-name + 53/push-ebx/outputs + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/no-inouts + 68/push 0/imm32/no-inouts + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edi 4/r32/esp +$test-emit-subx-stmt-select-primitive:initialize-primitive2-name: + # primitives->name = "increment" + 8d/copy-address *(edi+4) 0/r32/eax # Primitive-name + 4 + (copy-array Heap "increment" %eax) +$test-emit-subx-stmt-select-primitive:initialize-primitive2-subx-name: + # primitives->subx-name = "ff 0/subop/increment" + 8d/copy-address *(edi+0x1c) 0/r32/eax # Primitive-subx-name + 4 + (copy-array Heap "ff 0/subop/increment" %eax) +$test-emit-subx-stmt-select-primitive:initialize-primitive: + # var primitives/ebx: (addr primitive) + 57/push-edi + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/no-x32 + 68/push 0/imm32/no-xm32 + 68/push 0/imm32/no-disp32 + 68/push 0/imm32/no-imm8 + 68/push 0/imm32/no-imm32 + 68/push 0/imm32/no-r32 + 68/push 1/imm32/rm32-is-first-inout + 68/push 0/imm32/subx-name + 68/push 0/imm32/subx-name + 68/push 0/imm32/no-outputs + 68/push 0/imm32/no-outputs + 53/push-ebx/inouts # hack: reuse stmt-var from call stmt as (list var) in function declaration + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 89/<- %ebx 4/r32/esp +$test-emit-subx-stmt-select-primitive:initialize-primitive-name: + # primitives->name = "increment" + (copy-array Heap "increment" %ebx) # Primitive-name +$test-emit-subx-stmt-select-primitive:initialize-primitive-subx-name: + # primitives->subx-name = "ff 0/subop/increment" + 8d/copy-address *(ebx+0x18) 0/r32/eax # Primitive-subx-name + (copy-array Heap "ff 0/subop/increment" %eax) + # convert + c7 0/subop/copy *Curr-block-depth 0/imm32 + (emit-subx-stmt _test-output-buffered-file %esi %ebx 0 Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-emit-subx-stmt-select-primitive-2: + # Select the right primitive between overloads. + # increment foo + # => + # ff 0/subop/increment %eax # sub-optimal, but should suffice + # + # There's a variable on the var stack as follows: + # name: 'foo' + # type: int + # register: 'eax' + # + # There's two primitives, as follows: + # - name: 'increment' + # out: int/reg + # value: 'ff 0/subop/increment' + # - name: 'increment' + # inout: int/mem + # value: 'ff 0/subop/increment' + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) +$test-emit-subx-stmt-select-primitive-2:initialize-type: + # var type/ecx: (payload type-tree) = int + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 1/imm32/value:int + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-emit-subx-stmt-select-primitive-2:initialize-var: + # var var-foo/ecx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + 51/push-ecx + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-emit-subx-stmt-select-primitive-2:initialize-var-name: + # var-foo->name = "foo" + 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "foo" %eax) +$test-emit-subx-stmt-select-primitive-2:initialize-var-register: + # var-foo->register = "eax" + 8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4 + (copy-array Heap "eax" %eax) +$test-emit-subx-stmt-select-primitive-2:initialize-stmt-var: + # var operand/ebx: (payload stmt-var) + 68/push 0/imm32/is-deref:false + 68/push 0/imm32/next + 68/push 0/imm32/next + 51/push-ecx/var-foo + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ebx 4/r32/esp +$test-emit-subx-stmt-select-primitive-2:initialize-stmt: + # var stmt/esi: (addr statement) + 68/push 0/imm32/no-outputs + 68/push 0/imm32/no-outputs + 53/push-ebx/inouts + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/operation + 68/push 0/imm32/operation + 68/push 1/imm32 + 89/<- %esi 4/r32/esp +$test-emit-subx-stmt-select-primitive-2:initialize-stmt-operation: + # stmt->operation = "increment" + 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation + (copy-array Heap "increment" %eax) +$test-emit-subx-stmt-select-primitive-2:initialize-formal-var: + # var formal-var/ebx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + ff 6/subop/push *(ecx+0x10) # Var-type + payload alloc id + handle alloc id + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ebx 4/r32/esp +$test-emit-subx-stmt-select-primitive-2:initialize-formal-var-name: + # formal-var->name = "dummy" + 8d/copy-address *(ebx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "dummy" %eax) +$test-emit-subx-stmt-select-primitive-2:initialize-formal-register: + # formal-var->register = "*" + 8d/copy-address *(ebx+0x1c) 0/r32/eax # Var-register + 4 + (copy-array Heap "*" %eax) # Any-register +$test-emit-subx-stmt-select-primitive-2:initialize-var-list: + # var formal-outputs/ebx: (payload list stmt-var) + 68/push 0/imm32/next + 68/push 0/imm32/next + 53/push-ebx/formal-var + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ebx 4/r32/esp +$test-emit-subx-stmt-select-primitive-2:initialize-primitive2: + # var primitive2/edi: (payload primitive) + 68/push 0/imm32/next + 68/push 0/imm32/next + 68/push 0/imm32/no-x32 + 68/push 0/imm32/no-xm32 + 68/push 0/imm32/no-disp32 + 68/push 0/imm32/no-imm8 + 68/push 0/imm32/no-imm32 + 68/push 0/imm32/no-r32 + 68/push 3/imm32/rm32-is-first-output + 68/push 0/imm32/subx-name + 68/push 0/imm32/subx-name + 53/push-ebx/outputs + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/no-inouts + 68/push 0/imm32/no-inouts + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edi 4/r32/esp +$test-emit-subx-stmt-select-primitive-2:initialize-primitive2-name: + # primitives->name = "increment" + 8d/copy-address *(edi+4) 0/r32/eax # Primitive-name + 4 + (copy-array Heap "increment" %eax) +$test-emit-subx-stmt-select-primitive-2:initialize-primitive2-subx-name: + # primitives->subx-name = "ff 0/subop/increment" + 8d/copy-address *(edi+0x1c) 0/r32/eax # Primitive-subx-name + 4 + (copy-array Heap "ff 0/subop/increment" %eax) +$test-emit-subx-stmt-select-primitive-2:initialize-primitive: + # var primitives/ebx: (addr primitive) + 57/push-edi + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/no-x32 + 68/push 0/imm32/no-xm32 + 68/push 0/imm32/no-disp32 + 68/push 0/imm32/no-imm8 + 68/push 0/imm32/no-imm32 + 68/push 0/imm32/no-r32 + 68/push 1/imm32/rm32-is-first-inout + 68/push 0/imm32/subx-name + 68/push 0/imm32/subx-name + 68/push 0/imm32/no-outputs + 68/push 0/imm32/no-outputs + 53/push-ebx/inouts # hack: reuse stmt-var from call stmt as (list var) in function declaration + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 89/<- %ebx 4/r32/esp +$test-emit-subx-stmt-select-primitive-2:initialize-primitive-name: + # primitives->name = "increment" + (copy-array Heap "increment" %ebx) # Primitive-name +$test-emit-subx-stmt-select-primitive-2:initialize-primitive-subx-name: + # primitives->subx-name = "ff 0/subop/increment" + 8d/copy-address *(ebx+0x18) 0/r32/eax # Primitive-subx-name + (copy-array Heap "ff 0/subop/increment" %eax) + # convert + c7 0/subop/copy *Curr-block-depth 0/imm32 + (emit-subx-stmt _test-output-buffered-file %esi %ebx 0 Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive-2") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-increment-register: + # Select the right register between overloads. + # foo <- increment + # => + # 50/increment-eax + # + # There's a variable on the var stack as follows: + # name: 'foo' + # type: int + # register: 'eax' + # + # Primitives are the global definitions. + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) +$test-increment-register:initialize-type: + # var type/ecx: (payload type-tree) = int + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 1/imm32/value:int + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-increment-register:initialize-var: + # var var-foo/ecx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + 51/push-ecx + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-increment-register:initialize-var-name: + # var-foo->name = "foo" + 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "foo" %eax) +$test-increment-register:initialize-var-register: + # var-foo->register = "eax" + 8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4 + (copy-array Heap "eax" %eax) +$test-increment-register:initialize-stmt-var: + # var operand/ebx: (payload stmt-var) + 68/push 0/imm32/is-deref:false + 68/push 0/imm32/next + 68/push 0/imm32/next + 51/push-ecx/var-foo + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ebx 4/r32/esp +$test-increment-register:initialize-stmt: + # var stmt/esi: (addr statement) + 53/push-ebx/outputs + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/no-inouts + 68/push 0/imm32/no-inouts + 68/push 0/imm32/operation + 68/push 0/imm32/operation + 68/push 1/imm32 + 89/<- %esi 4/r32/esp +$test-increment-register:initialize-stmt-operation: + # stmt->operation = "increment" + 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation + (copy-array Heap "increment" %eax) + # convert + c7 0/subop/copy *Curr-block-depth 0/imm32 + (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-add-reg-to-reg: + # var1/reg <- add var2/reg + # => + # 01/add-to %var1 var2 + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) +$test-add-reg-to-reg:initialize-type: + # var type/ecx: (payload type-tree) = int + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 1/imm32/value:int + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-add-reg-to-reg:initialize-var1: + # var var1/ecx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + 51/push-ecx + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-add-reg-to-reg:initialize-var1-name: + # var1->name = "var1" + 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "var1" %eax) +$test-add-reg-to-reg:initialize-var1-register: + # var1->register = "eax" + 8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4 + (copy-array Heap "eax" %eax) +$test-add-reg-to-reg:initialize-var2: + # var var2/edx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + ff 6/subop/push *(ecx+0x10) + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edx 4/r32/esp +$test-add-reg-to-reg:initialize-var2-name: + # var2->name = "var2" + 8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "var2" %eax) +$test-add-reg-to-reg:initialize-var2-register: + # var2->register = "ecx" + 8d/copy-address *(edx+0x1c) 0/r32/eax # Var-register + 4 + (copy-array Heap "ecx" %eax) +$test-add-reg-to-reg:initialize-inouts: + # var inouts/esi: (payload stmt-var) = [var2] + 68/push 0/imm32/is-deref:false + 68/push 0/imm32/next + 68/push 0/imm32/next + 52/push-edx/var2 + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %esi 4/r32/esp +$test-add-reg-to-reg:initialize-outputs: + # var outputs/edi: (payload stmt-var) = [var1] + 68/push 0/imm32/is-deref:false + 68/push 0/imm32/next + 68/push 0/imm32/next + 51/push-ecx/var1 + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edi 4/r32/esp +$test-add-reg-to-reg:initialize-stmt: + # var stmt/esi: (addr statement) + 68/push 0/imm32/next + 68/push 0/imm32/next + 57/push-edi/outputs + 68/push 0x11/imm32/alloc-id:fake + 56/push-esi/inouts + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/operation + 68/push 0/imm32/operation + 68/push 1/imm32/tag:stmt1 + 89/<- %esi 4/r32/esp +$test-add-reg-to-reg:initialize-stmt-operation: + # stmt->operation = "add" + 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation + (copy-array Heap "add" %eax) + # convert + c7 0/subop/copy *Curr-block-depth 0/imm32 + (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-add-reg-to-mem: + # add-to var1 var2/reg + # => + # 01/add-to *(ebp+__) var2 + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) +$test-add-reg-to-mem:initialize-type: + # var type/ecx: (payload type-tree) = int + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 1/imm32/value:int + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-add-reg-to-mem:initialize-var1: + # var var1/ecx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 8/imm32/stack-offset + 68/push 1/imm32/block-depth + 51/push-ecx + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-add-reg-to-mem:initialize-var1-name: + # var1->name = "var1" + 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "var1" %eax) +$test-add-reg-to-mem:initialize-var2: + # var var2/edx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + ff 6/subop/push *(ecx+0x10) + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edx 4/r32/esp +$test-add-reg-to-mem:initialize-var2-name: + # var2->name = "var2" + 8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "var2" %eax) +$test-add-reg-to-mem:initialize-var2-register: + # var2->register = "ecx" + 8d/copy-address *(edx+0x1c) 0/r32/eax # Var-register + 4 + (copy-array Heap "ecx" %eax) +$test-add-reg-to-mem:initialize-inouts: + # var inouts/esi: (payload stmt-var) = [var2] + 68/push 0/imm32/is-deref:false + 68/push 0/imm32/next + 68/push 0/imm32/next + 52/push-edx/var2 + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %esi 4/r32/esp + # inouts = [var1, var2] + 68/push 0/imm32/is-deref:false + 56/push-esi/next + 68/push 0x11/imm32/alloc-id:fake + 51/push-ecx/var1 + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %esi 4/r32/esp +$test-add-reg-to-mem:initialize-stmt: + # var stmt/esi: (addr statement) + 68/push 0/imm32/next + 68/push 0/imm32/next + 68/push 0/imm32/outputs + 68/push 0/imm32/outputs + 56/push-esi/inouts + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/operation + 68/push 0/imm32/operation + 68/push 1/imm32/tag:stmt1 + 89/<- %esi 4/r32/esp +$test-add-reg-to-mem:initialize-stmt-operation: + # stmt->operation = "add-to" + 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation + (copy-array Heap "add-to" %eax) + # convert + c7 0/subop/copy *Curr-block-depth 0/imm32 + (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-add-mem-to-reg: + # var1/reg <- add var2 + # => + # 03/add *(ebp+__) var1 + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) +$test-add-mem-to-reg:initialize-type: + # var type/ecx: (payload type-tree) = int + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 1/imm32/value:int + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-add-mem-to-reg:initialize-var: + # var var1/ecx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + 51/push-ecx + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-add-mem-to-reg:initialize-var-name: + # var1->name = "foo" + 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "var1" %eax) +$test-add-mem-to-reg:initialize-var-register: + # var1->register = "eax" + 8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4 + (copy-array Heap "eax" %eax) +$test-add-mem-to-reg:initialize-var2: + # var var2/edx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 8/imm32/stack-offset + 68/push 1/imm32/block-depth + ff 6/subop/push *(ecx+0x10) + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edx 4/r32/esp +$test-add-mem-to-reg:initialize-var2-name: + # var2->name = "var2" + 8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "var2" %eax) +$test-add-mem-to-reg:initialize-inouts: + # var inouts/esi: (payload stmt-var) = [var2] + 68/push 0/imm32/is-deref:false + 68/push 0/imm32/next + 68/push 0/imm32/next + 52/push-edx/var2 + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %esi 4/r32/esp +$test-add-mem-to-reg:initialize-outputs: + # var outputs/edi: (payload stmt-var) = [var1] + 68/push 0/imm32/is-deref:false + 68/push 0/imm32/next + 68/push 0/imm32/next + 51/push-ecx/var1 + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edi 4/r32/esp +$test-add-mem-to-reg:initialize-stmt: + # var stmt/esi: (addr statement) + 68/push 0/imm32/next + 68/push 0/imm32/next + 57/push-edi/outputs + 68/push 0x11/imm32/alloc-id:fake + 56/push-esi/inouts + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/operation + 68/push 0/imm32/operation + 68/push 1/imm32/tag:stmt1 + 89/<- %esi 4/r32/esp +$test-add-mem-to-reg:initialize-stmt-operation: + # stmt->operation = "add" + 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation + (copy-array Heap "add" %eax) + # convert + c7 0/subop/copy *Curr-block-depth 0/imm32 + (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-add-literal-to-eax: + # var1/eax <- add 0x34 + # => + # 05/add-to-eax 0x34/imm32 + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) +$test-add-literal-to-eax:initialize-var-type: + # var type/ecx: (payload type-tree) = int + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 1/imm32/value:int + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-add-literal-to-eax:initialize-var: + # var v/ecx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + 51/push-ecx + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-add-literal-to-eax:initialize-var-name: + # v->name = "v" + 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "v" %eax) +$test-add-literal-to-eax:initialize-var-register: + # v->register = "eax" + 8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4 + (copy-array Heap "eax" %eax) +$test-add-literal-to-eax:initialize-literal-type: + # var type/edx: (payload type-tree) = literal + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 0/imm32/value:literal + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edx 4/r32/esp +$test-add-literal-to-eax:initialize-literal: + # var l/edx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + 52/push-edx + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edx 4/r32/esp +$test-add-literal-to-eax:initialize-literal-value: + # l->name = "0x34" + 8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "0x34" %eax) +$test-add-literal-to-eax:initialize-inouts: + # var inouts/esi: (payload stmt-var) = [l] + 68/push 0/imm32/is-deref:false + 68/push 0/imm32/next + 68/push 0/imm32/next + 52/push-edx/l + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %esi 4/r32/esp +$test-add-literal-to-eax:initialize-outputs: + # var outputs/edi: (payload stmt-var) = [v] + 68/push 0/imm32/is-deref:false + 68/push 0/imm32/next + 68/push 0/imm32/next + 51/push-ecx/v + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edi 4/r32/esp +$test-add-literal-to-eax:initialize-stmt: + # var stmt/esi: (addr statement) + 68/push 0/imm32/next + 68/push 0/imm32/next + 57/push-edi/outputs + 68/push 0x11/imm32/alloc-id:fake + 56/push-esi/inouts + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/operation + 68/push 0/imm32/operation + 68/push 1/imm32/tag:stmt1 + 89/<- %esi 4/r32/esp +$test-add-literal-to-eax:initialize-stmt-operation: + # stmt->operation = "add" + 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation + (copy-array Heap "add" %eax) + # convert + c7 0/subop/copy *Curr-block-depth 0/imm32 + (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-add-literal-to-reg: + # var1/ecx <- add 0x34 + # => + # 81 0/subop/add %ecx 0x34/imm32 + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) +$test-add-literal-to-reg:initialize-var-type: + # var type/ecx: (payload type-tree) = int + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 1/imm32/value:int + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-add-literal-to-reg:initialize-var: + # var v/ecx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + 51/push-ecx + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-add-literal-to-reg:initialize-var-name: + # v->name = "v" + 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "v" %eax) +$test-add-literal-to-reg:initialize-var-register: + # v->register = "ecx" + 8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4 + (copy-array Heap "ecx" %eax) +$test-add-literal-to-reg:initialize-literal-type: + # var type/edx: (payload type-tree) = literal + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 0/imm32/value:literal + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edx 4/r32/esp +$test-add-literal-to-reg:initialize-literal: + # var l/edx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + 52/push-edx + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edx 4/r32/esp +$test-add-literal-to-reg:initialize-literal-value: + # l->name = "0x34" + 8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "0x34" %eax) +$test-add-literal-to-reg:initialize-inouts: + # var inouts/esi: (payload stmt-var) = [l] + 68/push 0/imm32/is-deref:false + 68/push 0/imm32/next + 68/push 0/imm32/next + 52/push-edx/l + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %esi 4/r32/esp +$test-add-literal-to-reg:initialize-outputs: + # var outputs/edi: (payload stmt-var) = [v] + 68/push 0/imm32/is-deref:false + 68/push 0/imm32/next + 68/push 0/imm32/next + 51/push-ecx/v + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edi 4/r32/esp +$test-add-literal-to-reg:initialize-stmt: + # var stmt/esi: (addr statement) + 68/push 0/imm32/next + 68/push 0/imm32/next + 57/push-edi/outputs + 68/push 0x11/imm32/alloc-id:fake + 56/push-esi/inouts + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/operation + 68/push 0/imm32/operation + 68/push 1/imm32/tag:stmt1 + 89/<- %esi 4/r32/esp +$test-add-literal-to-reg:initialize-stmt-operation: + # stmt->operation = "add" + 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation + (copy-array Heap "add" %eax) + # convert + c7 0/subop/copy *Curr-block-depth 0/imm32 + (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-add-literal-to-mem: + # add-to var1, 0x34 + # => + # 81 0/subop/add %eax 0x34/imm32 + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) +$test-add-literal-to-mem:initialize-type: + # var type/ecx: (payload type-tree) = int + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 1/imm32/value:int + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-add-literal-to-mem:initialize-var1: + # var var1/ecx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 8/imm32/stack-offset + 68/push 1/imm32/block-depth + 51/push-ecx + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-add-literal-to-mem:initialize-var1-name: + # var1->name = "var1" + 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "var1" %eax) +$test-add-literal-to-mem:initialize-literal-type: + # var type/edx: (payload type-tree) = literal + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 0/imm32/value:literal + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edx 4/r32/esp +$test-add-literal-to-mem:initialize-literal: + # var l/edx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + 52/push-edx + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edx 4/r32/esp +$test-add-literal-to-mem:initialize-literal-value: + # l->name = "0x34" + 8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "0x34" %eax) +$test-add-literal-to-mem:initialize-inouts: + # var inouts/esi: (payload stmt-var) = [l] + 68/push 0/imm32/is-deref:false + 68/push 0/imm32/next + 68/push 0/imm32/next + 52/push-edx/l + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %esi 4/r32/esp + # var inouts = (handle stmt-var) = [var1, var2] + 68/push 0/imm32/is-deref:false + 56/push-esi/next + 68/push 0x11/imm32/alloc-id:fake + 51/push-ecx/var1 + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %esi 4/r32/esp +$test-add-literal-to-mem:initialize-stmt: + # var stmt/esi: (addr statement) + 68/push 0/imm32/next + 68/push 0/imm32/next + 68/push 0/imm32/outputs + 68/push 0/imm32/outputs + 56/push-esi/inouts + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/operation + 68/push 0/imm32/operation + 68/push 1/imm32/tag:stmt1 + 89/<- %esi 4/r32/esp +$test-add-literal-to-mem:initialize-stmt-operation: + # stmt->operation = "add-to" + 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation + (copy-array Heap "add-to" %eax) + # convert + c7 0/subop/copy *Curr-block-depth 0/imm32 + (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-shift-reg-by-literal: + # var1/ecx <- shift-left 2 + # => + # c1/shift 4/subop/left %ecx 2/imm8 + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) +$test-shift-reg-by-literal:initialize-var-type: + # var type/ecx: (payload type-tree) = int + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 1/imm32/value:int + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-shift-reg-by-literal:initialize-var: + # var v/ecx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + 51/push-ecx + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-shift-reg-by-literal:initialize-var-name: + # v->name = "v" + 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "v" %eax) +$test-shift-reg-by-literal:initialize-var-register: + # v->register = "ecx" + 8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4 + (copy-array Heap "ecx" %eax) +$test-shift-reg-by-literal:initialize-literal-type: + # var type/edx: (payload type-tree) = literal + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 0/imm32/value:literal + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edx 4/r32/esp +$test-shift-reg-by-literal:initialize-literal: + # var l/edx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + 52/push-edx + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edx 4/r32/esp +$test-shift-reg-by-literal:initialize-literal-value: + # l->name = "2" + 8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "2" %eax) +$test-shift-reg-by-literal:initialize-inouts: + # var inouts/esi: (payload stmt-var) = [l] + 68/push 0/imm32/is-deref:false + 68/push 0/imm32/next + 68/push 0/imm32/next + 52/push-edx/l + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %esi 4/r32/esp +$test-shift-reg-by-literal:initialize-outputs: + # var outputs/edi: (payload stmt-var) = [v] + 68/push 0/imm32/is-deref:false + 68/push 0/imm32/next + 68/push 0/imm32/next + 51/push-ecx/v + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edi 4/r32/esp +$test-shift-reg-by-literal:initialize-stmt: + # var stmt/esi: (addr statement) + 68/push 0/imm32/next + 68/push 0/imm32/next + 57/push-edi/outputs + 68/push 0x11/imm32/alloc-id:fake + 56/push-esi/inouts + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/operation + 68/push 0/imm32/operation + 68/push 1/imm32/tag:stmt1 + 89/<- %esi 4/r32/esp +$test-shift-reg-by-literal:initialize-stmt-operation: + # stmt->operation = "shift-left" + 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation + (copy-array Heap "shift-left" %eax) + # convert + c7 0/subop/copy *Curr-block-depth 0/imm32 + (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "c1/shift 4/subop/left %ecx 2/imm8" "F - test-shift-reg-by-literal") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-shift-mem-by-literal: + # shift-left var 3 + # => + # c1/shift 4/subop/left *(ebp+8) 3/imm8 + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) +$test-shift-mem-by-literal:initialize-type: + # var type/ecx: (payload type-tree) = int + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 1/imm32/value:int + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-shift-mem-by-literal:initialize-var1: + # var var1/ecx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 8/imm32/stack-offset + 68/push 1/imm32/block-depth + 51/push-ecx + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-shift-mem-by-literal:initialize-var1-name: + # var1->name = "var1" + 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "var1" %eax) +$test-shift-mem-by-literal:initialize-literal-type: + # var type/edx: (payload type-tree) = literal + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 0/imm32/value:literal + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edx 4/r32/esp +$test-shift-mem-by-literal:initialize-literal: + # var l/edx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + 52/push-edx + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edx 4/r32/esp +$test-shift-mem-by-literal:initialize-literal-value: + # l->name = "3" + 8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "3" %eax) +$test-shift-mem-by-literal:initialize-inouts: + # var inouts/esi: (payload stmt-var) = [l] + 68/push 0/imm32/is-deref:false + 68/push 0/imm32/next + 68/push 0/imm32/next + 52/push-edx/l + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %esi 4/r32/esp + # var inouts = (handle stmt-var) = [var1, var2] + 68/push 0/imm32/is-deref:false + 56/push-esi/next + 68/push 0x11/imm32/alloc-id:fake + 51/push-ecx/var1 + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %esi 4/r32/esp +$test-shift-mem-by-literal:initialize-stmt: + # var stmt/esi: (addr statement) + 68/push 0/imm32/next + 68/push 0/imm32/next + 68/push 0/imm32/outputs + 68/push 0/imm32/outputs + 56/push-esi/inouts + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/operation + 68/push 0/imm32/operation + 68/push 1/imm32/tag:stmt1 + 89/<- %esi 4/r32/esp +$test-shift-mem-by-literal:initialize-stmt-operation: + # stmt->operation = "shift-left" + 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation + (copy-array Heap "shift-left" %eax) + # convert + c7 0/subop/copy *Curr-block-depth 0/imm32 + (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "c1/shift 4/subop/left *(ebp+0x00000008) 3/imm8" "F - test-shift-mem-by-literal") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-compare-reg-with-reg: + # compare var1/ecx, var2/eax + # => + # 39/compare %ecx 0/r32/eax + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) +$test-compare-reg-with-reg:initialize-type: + # var type/ecx: (payload type-tree) = int + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 1/imm32/value:int + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-compare-reg-with-reg:initialize-var1: + # var var1/ecx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + 51/push-ecx + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-compare-reg-with-reg:initialize-var1-name: + # var1->name = "var1" + 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "var1" %eax) +$test-compare-reg-with-reg:initialize-var1-register: + # var1->register = "ecx" + 8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4 + (copy-array Heap "ecx" %eax) +$test-compare-reg-with-reg:initialize-var2: + # var var2/edx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + ff 6/subop/push *(ecx+0x10) + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edx 4/r32/esp +$test-compare-reg-with-reg:initialize-var2-name: + # var2->name = "var2" + 8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "var2" %eax) +$test-compare-reg-with-reg:initialize-var2-register: + # var2->register = "eax" + 8d/copy-address *(edx+0x1c) 0/r32/eax # Var-register + 4 + (copy-array Heap "eax" %eax) +$test-compare-reg-with-reg:initialize-inouts: + # var inouts/esi: (payload stmt-var) = [var2] + 68/push 0/imm32/is-deref:false + 68/push 0/imm32/next + 68/push 0/imm32/next + 52/push-edx/var2 + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %esi 4/r32/esp + # inouts = [var1, var2] + 68/push 0/imm32/is-deref:false + 56/push-esi/next + 68/push 0x11/imm32/alloc-id:fake + 51/push-ecx/var1 + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %esi 4/r32/esp +$test-compare-reg-with-reg:initialize-stmt: + # var stmt/esi: (addr statement) + 68/push 0/imm32/next + 68/push 0/imm32/next + 68/push 0/imm32/outputs + 68/push 0/imm32/outputs + 56/push-esi/inouts + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/operation + 68/push 0/imm32/operation + 68/push 1/imm32/tag:stmt1 + 89/<- %esi 4/r32/esp +$test-compare-reg-with-reg:initialize-stmt-operation: + # stmt->operation = "compare" + 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation + (copy-array Heap "compare" %eax) + # convert + c7 0/subop/copy *Curr-block-depth 0/imm32 + (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "39/compare-> %ecx 0x00000000/r32" "F - test-compare-reg-with-reg") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-compare-mem-with-reg: + # compare var1, var2/eax + # => + # 39/compare *(ebp+___) 0/r32/eax + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) +$test-compare-mem-with-reg:initialize-type: + # var type/ecx: (payload type-tree) = int + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 1/imm32/value:int + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-compare-mem-with-reg:initialize-var1: + # var var1/ecx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 8/imm32/stack-offset + 68/push 1/imm32/block-depth + 51/push-ecx + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-compare-mem-with-reg:initialize-var1-name: + # var1->name = "var1" + 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "var1" %eax) +$test-compare-mem-with-reg:initialize-var2: + # var var2/edx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + ff 6/subop/push *(ecx+0x10) + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edx 4/r32/esp +$test-compare-mem-with-reg:initialize-var2-name: + # var2->name = "var2" + 8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "var2" %eax) +$test-compare-mem-with-reg:initialize-var2-register: + # var2->register = "eax" + 8d/copy-address *(edx+0x1c) 0/r32/eax # Var-register + 4 + (copy-array Heap "eax" %eax) +$test-compare-mem-with-reg:initialize-inouts: + # var inouts/esi: (payload stmt-var) = [var2] + 68/push 0/imm32/is-deref:false + 68/push 0/imm32/next + 68/push 0/imm32/next + 52/push-edx/var2 + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %esi 4/r32/esp + # inouts = [var1, var2] + 68/push 0/imm32/is-deref:false + 56/push-esi/next + 68/push 0x11/imm32/alloc-id:fake + 51/push-ecx/var1 + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %esi 4/r32/esp +$test-compare-mem-with-reg:initialize-stmt: + # var stmt/esi: (addr statement) + 68/push 0/imm32/next + 68/push 0/imm32/next + 68/push 0/imm32/outputs + 68/push 0/imm32/outputs + 56/push-esi/inouts + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/operation + 68/push 0/imm32/operation + 68/push 1/imm32/tag:stmt1 + 89/<- %esi 4/r32/esp +$test-compare-mem-with-reg:initialize-stmt-operation: + # stmt->operation = "compare" + 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation + (copy-array Heap "compare" %eax) + # convert + c7 0/subop/copy *Curr-block-depth 0/imm32 + (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "39/compare-> *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-mem-with-reg") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-compare-reg-with-mem: + # compare var1/eax, var2 + # => + # 3b/compare<- *(ebp+___) 0/r32/eax + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) +$test-compare-reg-with-mem:initialize-type: + # var type/ecx: (payload type-tree) = int + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 1/imm32/value:int + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-compare-reg-with-mem:initialize-var1: + # var var1/ecx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + 51/push-ecx + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-compare-reg-with-mem:initialize-var1-name: + # var1->name = "var1" + 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "var1" %eax) +$test-compare-reg-with-mem:initialize-var1-register: + # var1->register = "eax" + 8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4 + (copy-array Heap "eax" %eax) +$test-compare-reg-with-mem:initialize-var2: + # var var2/edx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 8/imm32/stack-offset + 68/push 1/imm32/block-depth + ff 6/subop/push *(ecx+0x10) + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edx 4/r32/esp +$test-compare-reg-with-mem:initialize-var2-name: + # var2->name = "var2" + 8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "var2" %eax) +$test-compare-reg-with-mem:initialize-inouts: + # var inouts/esi: (payload stmt-var) = [var2] + 68/push 0/imm32/is-deref:false + 68/push 0/imm32/next + 68/push 0/imm32/next + 52/push-edx/var2 + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %esi 4/r32/esp + # inouts = [var1, var2] + 68/push 0/imm32/is-deref:false + 56/push-esi/next + 68/push 0x11/imm32/alloc-id:fake + 51/push-ecx/var1 + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %esi 4/r32/esp +$test-compare-reg-with-mem:initialize-stmt: + # var stmt/esi: (addr statement) + 68/push 0/imm32/next + 68/push 0/imm32/next + 68/push 0/imm32/outputs + 68/push 0/imm32/outputs + 56/push-esi/inouts + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/operation + 68/push 0/imm32/operation + 68/push 1/imm32/tag:stmt1 + 89/<- %esi 4/r32/esp +$test-compare-reg-with-mem:initialize-stmt-operation: + # stmt->operation = "compare" + 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation + (copy-array Heap "compare" %eax) + # convert + c7 0/subop/copy *Curr-block-depth 0/imm32 + (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "3b/compare<- *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-reg-with-mem") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-compare-mem-with-literal: + # compare var1, 0x34 + # => + # 81 7/subop/compare *(ebp+___) 0x34/imm32 + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) +$test-compare-mem-with-literal:initialize-type: + # var type/ecx: (payload type-tree) = int + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 1/imm32/value:int + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-compare-mem-with-literal:initialize-var1: + # var var1/ecx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 8/imm32/stack-offset + 68/push 1/imm32/block-depth + 51/push-ecx + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-compare-mem-with-literal:initialize-var1-name: + # var1->name = "var1" + 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "var1" %eax) +$test-compare-mem-with-literal:initialize-literal-type: + # var type/edx: (payload type-tree) = literal + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 0/imm32/value:literal + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edx 4/r32/esp +$test-compare-mem-with-literal:initialize-literal: + # var l/edx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + 52/push-edx + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edx 4/r32/esp +$test-compare-mem-with-literal:initialize-literal-value: + # l->name = "0x34" + 8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "0x34" %eax) +$test-compare-mem-with-literal:initialize-inouts: + # var inouts/esi: (payload stmt-var) = [l] + 68/push 0/imm32/is-deref:false + 68/push 0/imm32/next + 68/push 0/imm32/next + 52/push-edx/l + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %esi 4/r32/esp + # var inouts = (handle stmt-var) = [var1, var2] + 68/push 0/imm32/is-deref:false + 56/push-esi/next + 68/push 0x11/imm32/alloc-id:fake + 51/push-ecx/var1 + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %esi 4/r32/esp +$test-compare-mem-with-literal:initialize-stmt: + # var stmt/esi: (addr statement) + 68/push 0/imm32/next + 68/push 0/imm32/next + 68/push 0/imm32/outputs + 68/push 0/imm32/outputs + 56/push-esi/inouts + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/operation + 68/push 0/imm32/operation + 68/push 1/imm32/tag:stmt1 + 89/<- %esi 4/r32/esp +$test-compare-mem-with-literal:initialize-stmt-operation: + # stmt->operation = "compare" + 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation + (copy-array Heap "compare" %eax) + # convert + c7 0/subop/copy *Curr-block-depth 0/imm32 + (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "81 7/subop/compare *(ebp+0x00000008) 0x34/imm32" "F - test-compare-mem-with-literal") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-compare-eax-with-literal: + # compare var1/eax 0x34 + # => + # 3d/compare-eax-with 0x34/imm32 + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) +$test-compare-eax-with-literal:initialize-type: + # var type/ecx: (payload type-tree) = int + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 1/imm32/value:int + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-compare-eax-with-literal:initialize-var1: + # var var1/ecx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + 51/push-ecx + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-compare-eax-with-literal:initialize-var1-name: + # var1->name = "var1" + 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "var1" %eax) +$test-compare-eax-with-literal:initialize-var1-register: + # v->register = "eax" + 8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4 + (copy-array Heap "eax" %eax) +$test-compare-eax-with-literal:initialize-literal-type: + # var type/edx: (payload type-tree) = literal + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 0/imm32/value:literal + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edx 4/r32/esp +$test-compare-eax-with-literal:initialize-literal: + # var l/edx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + 52/push-edx + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edx 4/r32/esp +$test-compare-eax-with-literal:initialize-literal-value: + # l->name = "0x34" + 8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "0x34" %eax) +$test-compare-eax-with-literal:initialize-inouts: + # var inouts/esi: (payload stmt-var) = [l] + 68/push 0/imm32/is-deref:false + 68/push 0/imm32/next + 68/push 0/imm32/next + 52/push-edx/l + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %esi 4/r32/esp + # var inouts = (handle stmt-var) = [var1, var2] + 68/push 0/imm32/is-deref:false + 56/push-esi/next + 68/push 0x11/imm32/alloc-id:fake + 51/push-ecx/var1 + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %esi 4/r32/esp +$test-compare-eax-with-literal:initialize-stmt: + # var stmt/esi: (addr statement) + 68/push 0/imm32/next + 68/push 0/imm32/next + 68/push 0/imm32/outputs + 68/push 0/imm32/outputs + 56/push-esi/inouts + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/operation + 68/push 0/imm32/operation + 68/push 1/imm32/tag:stmt1 + 89/<- %esi 4/r32/esp +$test-compare-eax-with-literal:initialize-stmt-operation: + # stmt->operation = "compare" + 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation + (copy-array Heap "compare" %eax) + # convert + c7 0/subop/copy *Curr-block-depth 0/imm32 + (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "3d/compare-eax-with 0x34/imm32" "F - test-compare-eax-with-literal") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-compare-reg-with-literal: + # compare var1/ecx 0x34 + # => + # 81 7/subop/compare %ecx 0x34/imm32 + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) +$test-compare-reg-with-literal:initialize-type: + # var type/ecx: (payload type-tree) = int + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 1/imm32/value:int + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-compare-reg-with-literal:initialize-var1: + # var var1/ecx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + 51/push-ecx + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-compare-reg-with-literal:initialize-var1-name: + # var1->name = "var1" + 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "var1" %eax) +$test-compare-reg-with-literal:initialize-var1-register: + # v->register = "ecx" + 8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4 + (copy-array Heap "ecx" %eax) +$test-compare-reg-with-literal:initialize-literal-type: + # var type/edx: (payload type-tree) = literal + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 0/imm32/value:literal + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edx 4/r32/esp +$test-compare-reg-with-literal:initialize-literal: + # var l/edx: (payload var) + 68/push 0/imm32/register + 68/push 0/imm32/register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + 52/push-edx + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %edx 4/r32/esp +$test-compare-reg-with-literal:initialize-literal-value: + # l->name = "0x34" + 8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "0x34" %eax) +$test-compare-reg-with-literal:initialize-inouts: + # var inouts/esi: (payload stmt-var) = [l] + 68/push 0/imm32/is-deref:false + 68/push 0/imm32/next + 68/push 0/imm32/next + 52/push-edx/l + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %esi 4/r32/esp + # var inouts = (handle stmt-var) = [var1, var2] + 68/push 0/imm32/is-deref:false + 56/push-esi/next + 68/push 0x11/imm32/alloc-id:fake + 51/push-ecx/var1 + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %esi 4/r32/esp +$test-compare-reg-with-literal:initialize-stmt: + # var stmt/esi: (addr statement) + 68/push 0/imm32/next + 68/push 0/imm32/next + 68/push 0/imm32/outputs + 68/push 0/imm32/outputs + 56/push-esi/inouts + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/operation + 68/push 0/imm32/operation + 68/push 1/imm32/tag:stmt1 + 89/<- %esi 4/r32/esp +$test-compare-reg-with-literal:initialize-stmt-operation: + # stmt->operation = "compare" + 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation + (copy-array Heap "compare" %eax) + # convert + c7 0/subop/copy *Curr-block-depth 0/imm32 + (emit-subx-stmt _test-output-buffered-file %esi Primitives 0 Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "81 7/subop/compare %ecx 0x34/imm32" "F - test-compare-reg-with-literal") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-emit-subx-stmt-function-call: + # Call a function on a variable on the stack. + # f foo + # => + # (f *(ebp-8)) + # (Changing the function name supports overloading in general, but here it + # just serves to help disambiguate things.) + # + # There's a variable on the var stack as follows: + # name: 'foo' + # type: int + # stack-offset: -8 + # + # There's nothing in primitives. + # + # We don't perform any checking here on the type of 'f'. + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) +$test-emit-subx-function-call:initialize-type: + # var type/ecx: (payload type-tree) = int + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 1/imm32/value:int + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-emit-subx-function-call:initialize-var: + # var var-foo/ecx: (payload var) = var(type) + 68/push 0/imm32/no-register + 68/push 0/imm32/no-register + 68/push -8/imm32/stack-offset + 68/push 1/imm32/block-depth + 51/push-ecx/type + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-emit-subx-function-call:initialize-var-name: + # var-foo->name = "foo" + 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "foo" %eax) +$test-emit-subx-function-call:initialize-stmt-var: + # var operand/ebx: (payload stmt-var) = stmt-var(var-foo) + 68/push 0/imm32/is-deref:false + 68/push 0/imm32/next + 68/push 0/imm32/next + 51/push-ecx/var-foo + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ebx 4/r32/esp +$test-emit-subx-function-call:initialize-stmt: + # var stmt/esi: (addr statement) + 68/push 0/imm32/no-outputs + 68/push 0/imm32/no-outputs + 53/push-ebx/inouts + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/operation + 68/push 0/imm32/operation + 68/push 1/imm32/tag + 89/<- %esi 4/r32/esp +$test-emit-subx-function-call:initialize-stmt-operation: + # stmt->operation = "f" + 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation + (copy-array Heap "f" %eax) + # convert + c7 0/subop/copy *Curr-block-depth 0/imm32 + (emit-subx-stmt _test-output-buffered-file %esi 0 0 Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "(f *(ebp+0xfffffff8))" "F - test-emit-subx-stmt-function-call") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-emit-subx-stmt-function-call-with-literal-arg: + # Call a function on a literal. + # f 0x34 + # => + # (f2 0x34) + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + (clear-stream _test-output-stream) + (clear-stream $_test-output-buffered-file->buffer) +$test-emit-subx-function-call-with-literal-arg:initialize-type: + # var type/ecx: (payload type-tree) = int + 68/push 0/imm32/right:null + 68/push 0/imm32/right:null + 68/push 0/imm32/left:unused + 68/push 0/imm32/value:literal + 68/push 1/imm32/is-atom?:true + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-emit-subx-function-call-with-literal-arg:initialize-var: + # var var-foo/ecx: (payload var) = var(lit) + 68/push 0/imm32/no-register + 68/push 0/imm32/no-register + 68/push 0/imm32/no-stack-offset + 68/push 1/imm32/block-depth + 51/push-ecx/type + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/name + 68/push 0/imm32/name + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ecx 4/r32/esp +$test-emit-subx-function-call-with-literal-arg:initialize-var-name: + # var-foo->name = "0x34" + 8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4 + (copy-array Heap "0x34" %eax) +$test-emit-subx-function-call-with-literal-arg:initialize-stmt-var: + # var operand/ebx: (payload stmt-var) = stmt-var(var-foo) + 68/push 0/imm32/is-deref:false + 68/push 0/imm32/next + 68/push 0/imm32/next + 51/push-ecx/var-foo + 68/push 0x11/imm32/alloc-id:fake + 68/push 0x11/imm32/alloc-id:fake:payload + 89/<- %ebx 4/r32/esp +$test-emit-subx-function-call-with-literal-arg:initialize-stmt: + # var stmt/esi: (addr statement) + 68/push 0/imm32/no-outputs + 68/push 0/imm32/no-outputs + 53/push-ebx/inouts + 68/push 0x11/imm32/alloc-id:fake + 68/push 0/imm32/operation + 68/push 0/imm32/operation + 68/push 1/imm32/tag + 89/<- %esi 4/r32/esp +$test-emit-subx-function-call-with-literal-arg:initialize-stmt-operation: + # stmt->operation = "f" + 8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation + (copy-array Heap "f" %eax) + # convert + c7 0/subop/copy *Curr-block-depth 0/imm32 + (emit-subx-stmt _test-output-buffered-file %esi 0 %ebx 0 Stderr 0) + (flush _test-output-buffered-file) +#? # dump _test-output-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-output-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-output-stream) +#? # }}} + # check output + (check-next-stream-line-equal _test-output-stream "(f 0x34)" "F - test-emit-subx-stmt-function-call-with-literal-arg") + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +emit-indent: # out: (addr buffered-file), n: int + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + # var i/eax: int = n + 8b/-> *(ebp+0xc) 0/r32/eax + { + # if (i <= 0) break + 3d/compare-eax-with 0/imm32 + 7e/jump-if-<= break/disp8 + (write-buffered *(ebp+8) " ") + 48/decrement-eax + eb/jump loop/disp8 + } +$emit-indent:end: + # . restore registers + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +emit-subx-prologue: # out: (addr buffered-file) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # + (write-buffered *(ebp+8) " # . prologue\n") + (write-buffered *(ebp+8) " 55/push-ebp\n") + (write-buffered *(ebp+8) " 89/<- %ebp 4/r32/esp\n") +$emit-subx-prologue:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +emit-subx-epilogue: # out: (addr buffered-file) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # + (write-buffered *(ebp+8) " # . epilogue\n") + (write-buffered *(ebp+8) " 89/<- %esp 5/r32/ebp\n") + (write-buffered *(ebp+8) " 5d/pop-to-ebp\n") + (write-buffered *(ebp+8) " c3/return\n") +$emit-subx-epilogue:end: + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return |