# 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 -> result/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.
#
# 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
# Keep Primitive-type-ids in sync if you add types here.
# 0x40
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 0/imm32
Primitive-type-ids: # (addr int)
0x40
# == 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-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-returns-result:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(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 -> result/eax: int {\n")
(write _test-input-stream " result <- copy a\n")
(write _test-input-stream " result <- 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-returns-result/0")
(check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-returns-result/1")
(check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-returns-result/2")
(check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-returns-result/3")
(check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-returns-result/4")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-returns-result/5")
(check-next-stream-line-equal _test-output-stream " 8b/-> *(ebp+0x00000008) 0x00000000/r32" "F - test-convert-function-returns-result/6")
(check-next-stream-line-equal _test-output-stream " 40/increment-eax" "F - test-convert-function-returns-result/7")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-returns-result/8")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-returns-result/9")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-returns-result/10")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-returns-result/11")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-returns-result/12")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-returns-result/13")
# . epilogue
89/<- %esp 5/r32/ebp
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 -> result/eax: int {\n")
(write _test-input-stream " result <- copy a\n")
(write _test-input-stream " result <- add 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)
#? # 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 " 8b/-> *(ebp+0x00000008) 0x00000000/r32" "F - test-convert-function-with-literal-arg/6")
(check-next-stream-line-equal _test-output-stream " 05/add-to-eax 1/imm32" "F - test-convert-function-with-literal-arg/7")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-literal-arg/8")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-literal-arg/9")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-literal-arg/10")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-literal-arg/11")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-literal-arg/12")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-literal-arg/13")
# . 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 -> result/ebx: int {\n")
(write _test-input-stream " result <- copy a\n")
(write _test-input-stream " result <- add 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)
#? # 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 " 8b/-> *(ebp+0x00000008) 0x00000003/r32" "F - test-convert-function-with-literal-arg-2/6")
(check-next-stream-line-equal _test-output-stream " 81 0/subop/add %ebx 1/imm32" "F - test-convert-function-with-literal-arg-2/7")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-literal-arg-2/8")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-literal-arg-2/9")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-literal-arg-2/10")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-literal-arg-2/11")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-literal-arg-2/12")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-literal-arg-2/13")
# . 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 -> result/ebx: int {\n")
(write _test-input-stream " result <- do-add 3 4\n")
(write _test-input-stream "}\n")
(write _test-input-stream "fn do-add a: int, b: int -> result/ebx: int {\n")
(write _test-input-stream " result <- copy a\n")
(write _test-input-stream " result <- add 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 "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 " (do-add 3 4)" "F - test-convert-function-call-with-literal-arg/6")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-call-with-literal-arg/7")
(check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-literal-arg/8")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-literal-arg/9")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-literal-arg/10")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-literal-arg/11")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-literal-arg/12")
(check-next-stream-line-equal _test-output-stream "do-add:" "F - test-convert-function-call-with-literal-arg/13")
(check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-literal-arg/14")
(check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call-with-literal-arg/15")
(check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-literal-arg/16")
(check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-call-with-literal-arg/17")
(check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:loop:" "F - test-convert-function-call-with-literal-arg/18")
(check-next-stream-line-equal _test-output-stream " 8b/-> *(ebp+0x00000008) 0x00000003/r32" "F - test-convert-function-call-with-literal-arg/19")
(check-next-stream-line-equal _test-output-stream " 03/add *(ebp+0x0000000c) 0x00000003/r32" "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:break:" "F - test-convert-function-call-with-literal-arg/22")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-literal-arg/23")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-literal-arg/24")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-literal-arg/25")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-literal-arg/26")
# . 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 -> result/ebx: int {\n")
(write _test-input-stream " result <- do-add 3 4\n")
(write _test-input-stream "}\n")
(write _test-input-stream "sig do-add a: int, b: int -> result/ebx: 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 " (do-add 3 4)" "F - test-convert-function-call-with-signature/6")
(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-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-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 -> result/ebx: int {\n")
(write _test-input-stream " result <- foo\n")
(write _test-input-stream "}\n")
(write _test-input-stream "fn foo -> result/ebx: int {\n")
(write _test-input-stream " result <- 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 "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 " (foo)" "F - test-convert-function-call/6")
(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 " bb/copy-to-ebx 3/imm32" "F - test-convert-function-call/19")
(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 -> a/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 -> a/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 -> a/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 -> a/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
# variables of type 'byte' are not allowed on the stack
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 " ff 6/subop/push %edx" "F - test-convert-function-with-byte-operations/11")
(check-next-stream-line-equal _test-output-stream " ba/copy-to-edx 0/imm32" "F - test-convert-function-with-byte-operations/12")
(check-next-stream-line-equal _test-output-stream " 8a/byte-> *edx 0x00000001/r32" "F - test-convert-function-with-byte-operations/13")
(check-next-stream-line-equal _test-output-stream " 88/byte<- *edx 0x00000000/r32" "F - test-convert-function-with-byte-operations/14")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %edx" "F - test-convert-function-with-byte-operations/15")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-function-with-byte-operations/16")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-function-with-byte-operations/17")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-byte-operations/18")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-byte-operations/19")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-byte-operations/20")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-byte-operations/21")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-byte-operations/22")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-byte-operations/23")
# . epilogue
89/<- %esp 5/r32/ebp
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-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
_pending-test-clobber-dead-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 "}\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-clobber-dead-local/0")
(check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-clobber-dead-local/1")
(check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-clobber-dead-local/2")
(check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-clobber-dead-local/3")
(check-next-stream-line-equal _test-output-stream " {" "F - test-clobber-dead-local/4")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-clobber-dead-local/5")
(check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-clobber-dead-local/6")
(check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-clobber-dead-local/7")
(check-next-stream-line-equal _test-output-stream " {" "F - test-clobber-dead-local/8")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-clobber-dead-local/9")
(check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 4/imm32" "F - test-clobber-dead-local/10") # no push/pop here
(check-next-stream-line-equal _test-output-stream " }" "F - test-clobber-dead-local/11")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-clobber-dead-local/12")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-clobber-dead-local/13")
(check-next-stream-line-equal _test-output-stream " }" "F - test-clobber-dead-local/14")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-clobber-dead-local/15")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-clobber-dead-local/16")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-clobber-dead-local/17")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-clobber-dead-local/18")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-clobber-dead-local/19")
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
test-shadow-live-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-live-local/0")
(check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-shadow-live-local/1")
(check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-shadow-live-local/2")
(check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-shadow-live-local/3")
(check-next-stream-line-equal _test-output-stream " {" "F - test-shadow-live-local/4")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-shadow-live-local/5")
(check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-shadow-live-local/6")
(check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-shadow-live-local/7")
(check-next-stream-line-equal _test-output-stream " {" "F - test-shadow-live-local/8")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-shadow-live-local/9")
(check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-shadow-live-local/10")
(check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 4/imm32" "F - test-shadow-live-local/11")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-shadow-live-local/12")
(check-next-stream-line-equal _test-output-stream " }" "F - test-shadow-live-local/13")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-shadow-live-local/14")
(check-next-stream-line-equal _test-output-stream " 41/increment-ecx" "F - test-shadow-live-local/15")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-shadow-live-local/16")
(check-next-stream-line-equal _test-output-stream " }" "F - test-shadow-live-local/17")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-shadow-live-local/18")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-shadow-live-local/19")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-shadow-live-local/20")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-shadow-live-local/21")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-shadow-live-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-shadow-live-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)
#
(write _test-input-stream "fn foo -> x/ecx: int {\n")
(write _test-input-stream " x <- 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-live-output/0")
(check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-shadow-live-output/1")
(check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-shadow-live-output/2")
(check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-shadow-live-output/3")
(check-next-stream-line-equal _test-output-stream " {" "F - test-shadow-live-output/4")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-shadow-live-output/5")
(check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-shadow-live-output/7") # no push because it's an output reg
(check-next-stream-line-equal _test-output-stream " {" "F - test-shadow-live-output/8")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-shadow-live-output/9")
(check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-shadow-live-output/10")
(check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 4/imm32" "F - test-shadow-live-output/11")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-shadow-live-output/12")
(check-next-stream-line-equal _test-output-stream " }" "F - test-shadow-live-output/13")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-shadow-live-output/14")
(check-next-stream-line-equal _test-output-stream " 41/increment-ecx" "F - test-shadow-live-output/15")
(check-next-stream-line-equal _test-output-stream " }" "F - test-shadow-live-output/17")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-shadow-live-output/18")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-shadow-live-output/19")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-shadow-live-output/20")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-shadow-live-output/21")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-shadow-live-output/21")
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
test-stmt-defines-output-in-same-register-as-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 -> x/ecx: int {\n")
(write _test-input-stream " var y/ecx: int <- copy 4\n")
(write _test-input-stream " x <- copy y\n") # writing to a fn output is currently the only way for a statement to define a new var
(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; we looked up 'y' correctly before pushing the binding for 'x'
(check-stream-equal _test-error-stream "" "F - test-stmt-defines-output-in-same-register-as-inout: 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-local-clobbered-by-fn-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)
#
(write _test-input-stream "fn foo -> x/ecx: int {\n")
(write _test-input-stream " var y/ecx: int <- copy 4\n")
(write _test-input-stream " x <- 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-local-clobbered-by-fn-output/0")
(check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-local-clobbered-by-fn-output/1")
(check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-local-clobbered-by-fn-output/2")
(check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-local-clobbered-by-fn-output/3")
(check-next-stream-line-equal _test-output-stream " {" "F - test-local-clobbered-by-fn-output/4")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-local-clobbered-by-fn-output/5")
(check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 4/imm32" "F - test-local-clobbered-by-fn-output/6") # no push because it's an output reg
(check-next-stream-line-equal _test-output-stream " 89/<- %ecx 0x00000001/r32" "F - test-local-clobbered-by-fn-output/7")
(check-next-stream-line-equal _test-output-stream " }" "F - test-local-clobbered-by-fn-output/8")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-local-clobbered-by-fn-output/9")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-local-clobbered-by-fn-output/10")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-local-clobbered-by-fn-output/11")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-local-clobbered-by-fn-output/12")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-local-clobbered-by-fn-output/13")
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
test-read-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)
#
(write _test-input-stream "fn foo -> x/ecx: int {\n")
(write _test-input-stream " x <- copy 0x34\n")
(write _test-input-stream " compare x, 0x35\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-read-output/0")
(check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-read-output/1")
(check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-read-output/2")
(check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-read-output/3")
(check-next-stream-line-equal _test-output-stream " {" "F - test-read-output/4")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-read-output/5")
(check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 0x34/imm32" "F - test-read-output/6")
(check-next-stream-line-equal _test-output-stream " 81 7/subop/compare %ecx 0x35/imm32" "F - test-read-output/7")
(check-next-stream-line-equal _test-output-stream " }" "F - test-read-output/8")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-read-output/9")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-read-output/10")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-read-output/11")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-read-output/12")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-read-output/13")
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
test-fn-output-written-in-inner-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 -> out/edi: int {\n")
(write _test-input-stream " var a/eax: int <- copy 3\n") # define outer local
(write _test-input-stream " {\n")
(write _test-input-stream " var a/ecx: int <- copy 4\n") # shadow outer local
(write _test-input-stream " out <- copy a\n") # write to fn output
(write _test-input-stream " }\n")
(write _test-input-stream " compare a, 0\n") # use outer local
(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 error; defining 'out' didn't interfere with the reclamation of 'b'
# check output
(check-next-stream-line-equal _test-output-stream "foo:" "F - test-fn-output-written-in-inner-block/0")
(check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-fn-output-written-in-inner-block/1")
(check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-fn-output-written-in-inner-block/2")
(check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-fn-output-written-in-inner-block/3")
(check-next-stream-line-equal _test-output-stream " {" "F - test-fn-output-written-in-inner-block/4")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-fn-output-written-in-inner-block/5")
(check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-fn-output-written-in-inner-block/6")
(check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 3/imm32" "F - test-fn-output-written-in-inner-block/7")
(check-next-stream-line-equal _test-output-stream " {" "F - test-fn-output-written-in-inner-block/8")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-fn-output-written-in-inner-block/9")
(check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-fn-output-written-in-inner-block/10")
(check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 4/imm32" "F - test-fn-output-written-in-inner-block/10")
(check-next-stream-line-equal _test-output-stream " 89/<- %edi 0x00000001/r32" "F - test-fn-output-written-in-inner-block/11")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-fn-output-written-in-inner-block/12")
(check-next-stream-line-equal _test-output-stream " }" "F - test-fn-output-written-in-inner-block/13")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-fn-output-written-in-inner-block/14")
(check-next-stream-line-equal _test-output-stream " 3d/compare-eax-with 0/imm32" "F - test-fn-output-written-in-inner-block/15")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-fn-output-written-in-inner-block/16")
(check-next-stream-line-equal _test-output-stream " }" "F - test-fn-output-written-in-inner-block/17")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-fn-output-written-in-inner-block/18")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-fn-output-written-in-inner-block/19")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-fn-output-written-in-inner-block/20")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-fn-output-written-in-inner-block/21")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-fn-output-written-in-inner-block/22")
# . 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-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-convert-length-of-array-on-stack/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-convert-length-of-array-on-stack/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 %xmm1 0x00000005/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 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 _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 0/imm32" "F - test-reg-var-def-with-read-of-same-register/7")
(check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-reg-var-def-with-read-of-same-register/8")
(check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-reg-var-def-with-read-of-same-register/9")
(check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx<<0x00000002 + 4) 0x00000000/r32" "F - test-reg-var-def-with-read-of-same-register/11")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-reg-var-def-with-read-of-same-register/13")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-reg-var-def-with-read-of-same-register/14")
(check-next-stream-line-equal _test-output-stream " }" "F - test-reg-var-def-with-read-of-same-register/15")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-reg-var-def-with-read-of-same-register/16")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-reg-var-def-with-read-of-same-register/17")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-reg-var-def-with-read-of-same-register/18")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-reg-var-def-with-read-of-same-register/19")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-reg-var-def-with-read-of-same-register/20")
# 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 " 8d/copy-address *(eax + ecx<<0x00000002 + 4) 0x00000000/r32" "F - test-convert-index-into-array/10")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array/11")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array/12")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array/13")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array/14")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array/15")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array/16")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array/17")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array/18")
# . 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 " 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/13")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-of-bytes/14")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-of-bytes/15")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-of-bytes/16")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-of-bytes/17")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-of-bytes/18")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-of-bytes/19")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-of-bytes/20")
# . 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")
# 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/8")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-with-literal/9")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-with-literal/10")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-with-literal/11")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-with-literal/12")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-with-literal/13")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-with-literal/14")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-with-literal/15")
# . 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")
# 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")
# 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/10")
# reclaim idx
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-on-stack/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/12")
#
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-on-stack/13")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-on-stack/14")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-on-stack/15")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-on-stack/16")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-on-stack/17")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-on-stack/18")
# . 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")
# 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/9")
# 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/10")
# 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/11")
#
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-on-stack-with-literal/12")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-on-stack-with-literal/13")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-on-stack-with-literal/14")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-on-stack-with-literal/15")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-on-stack-with-literal/16")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-on-stack-with-literal/17")
# . 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")
# 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/9")
# 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/10")
# 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/11")
#
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/12")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/13")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/14")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/15")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/16")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/17")
# . 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 " 8d/copy-address *(eax + ecx + 4) 0x00000000/r32" "F - test-convert-index-into-array-using-offset/11")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-using-offset/12")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-using-offset/13")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-using-offset/14")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-using-offset/15")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-using-offset/16")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-using-offset/17")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-using-offset/18")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-using-offset/19")
# . 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 " 8d/copy-address *(eax + ecx + 4) 0x00000000/r32" "F - test-convert-index-into-array-of-bytes-using-offset/11")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-of-bytes-using-offset/12")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-of-bytes-using-offset/13")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-of-bytes-using-offset/14")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-of-bytes-using-offset/15")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-of-bytes-using-offset/16")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-of-bytes-using-offset/17")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-of-bytes-using-offset/18")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-of-bytes-using-offset/19")
# . 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 " 8d/copy-address *(eax + ecx + 4) 0x00000000/r32" "F - test-convert-index-into-array-using-offset-on-stack/11")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-using-offset-on-stack/12")
(check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-index-into-array-using-offset-on-stack/13")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-using-offset-on-stack/14")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-using-offset-on-stack/15")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-using-offset-on-stack/16")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-using-offset-on-stack/17")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-using-offset-on-stack/18")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-using-offset-on-stack/19")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-using-offset-on-stack/20")
# . 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 " 8d/copy-address *(eax + ecx + 4) 0x00000000/r32" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/11")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/12")
(check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/13")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/14")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/15")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/16")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/17")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/18")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/19")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/20")
# . 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 int) <- copy x\n")
(write _test-input-stream " increment *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 " ff 0/subop/increment *ecx" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/27")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/28")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/29")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/30")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/31")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/32")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/33")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/34")
# . 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: only non-addr scalar args permitted" "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-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-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 address" "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 address" "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 " 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/13")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-array-of-user-defined-types/14")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-array-of-user-defined-types/15")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-array-of-user-defined-types/16")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-array-of-user-defined-types/17")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-array-of-user-defined-types/18")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-array-of-user-defined-types/19")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-array-of-user-defined-types/20")
# . 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: (addr t) <- 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: (addr t) <- 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: (addr t) <- 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: (addr t) <- 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-array-base-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 {\n")
(write _test-input-stream " var a/eax: (array int 3) <- copy 0\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-base-in-register: output should be empty")
(check-next-stream-line-equal _test-error-stream "fn foo: stmt index: var 'a' is an array, and so must live on the stack" "F - test-index-with-array-base-in-register: error message")
# check that stop(1) was called
(check-ints-equal *(edx+4) 2 "F - test-index-with-array-base-in-register: 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 address" "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 address" "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-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 address" "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
#######################################################
# 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 -> y/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)
# 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
# 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)
(parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x14) *(ebp+0x18))
# 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-header: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
# 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)
(parse-var-with-type %ecx *(ebp+8) %ebx *(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
# 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+0x10) %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
# scenarios considered:
# ✓ fn foo
# ✗ fn foo {
# ✓ fn foo x
# ✓ fn foo x: int
# ✓ fn foo x: int -> y/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
# 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)
(parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x10) *(ebp+0x14))
# 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)
(parse-var-with-type %ecx *(ebp+8) %ebx *(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
# 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
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
(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
(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
(clear-stream _test-input-stream)
(write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/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 "x" "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 "y" "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
# WARNING: modifies name
parse-var-with-type: # name: (addr slice), first-line: (addr stream byte), out: (addr handle var), 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+0x14) *(ebp+0x18))
$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("var should have form 'name: type' in '" line "'\n")
(write-buffered *(ebp+0x14) "var should have form 'name: type' in '")
(flush *(ebp+0x14))
(rewind-stream *(ebp+0xc))
(write-stream-data *(ebp+0x14) *(ebp+0xc))
(write-buffered *(ebp+0x14) "'\n")
(flush *(ebp+0x14))
(stop *(ebp+0x18) 1)
# never gets here
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
#
(is-hex-int? %ecx) # => eax
3d/compare-eax-and 0/imm32/false
74/jump-if-= break/disp8
$parse-type:int:
(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 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 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 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 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 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
53/push-ebx
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)
(parse-var-with-type %ecx *(ebp+8) %edx *(ebp+0x18) *(ebp+0x1c))
# var v-addr/eax: (addr var)
(lookup *edx *(edx+4)) # => eax
# v->block-depth = *Curr-block-depth
8b/-> *Curr-block-depth 3/r32/ebx
89/<- *(eax+0x10) 3/r32/ebx # Var-block-depth
# either v has no register and there's no more to this line
8b/-> *(eax+0x18) 0/r32/eax # Var-register
3d/compare-eax-and 0/imm32
{
75/jump-if-!= break/disp8
# TODO: disallow vars of type 'byte' on the stack
# 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
# TODO: disallow vars of type 'byte' in registers 'esi' or 'edi'
# 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
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-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:
(rewind-stream *(ebp+8))
# 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
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)
# Carefully push any outputs on the vars stack _after_ reading the inputs
# that may conflict with them.
#
# The only situation in which outputs are pushed here (when it's not a
# 'var' vardef stmt), and so can possibly conflict with inputs, is if the
# output is a function output.
#
# 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-or-find-in-fn-outputs(name, vars, fn)
# out-addr->outputs = append(v, out-addr->outputs)
# add-operation-and-inputs-to-stmt(out-addr, line, vars)
# for output in stmt->outputs:
# maybe-define-var(output, 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
# 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
ff 0/subop/increment *ecx
ba/copy-to-edx 1/imm32/true
}
# 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-or-find-in-fn-outputs %ecx *(ebp+0xc) *(ebp+0x10) %ebx *(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) %edx %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:define-outputs:
# var output/edi: (addr stmt-var) = lookup(out-addr->outputs)
(lookup *(edi+0x14) *(edi+0x18)) # Stmt1-outputs Stmt1-outputs => eax
89/<- %edi 0/r32/eax
{
$parse-mu-stmt:define-outputs-loop:
# if (output == null) break
81 7/subop/compare %edi 0/imm32
74/jump-if-= break/disp8
#
(maybe-define-var *edi *(edi+4) *(ebp+0xc)) # if output is a deref, then it's already been defined,
# and must be in vars. This call will be a no-op, but safe.
# output = output->next
(lookup *(edi+8) *(edi+0xc)) # Stmt-var-next Stmt-var-next => eax
89/<- %edi 0/r32/eax
#
eb/jump loop/disp8
}
$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) "invalid identifier '")
(write-slice-buffered *(ebp+0x18) %ecx)
(write-buffered *(ebp+0x18) "'\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))
$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
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 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
# return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found
lookup-var-or-find-in-fn-outputs: # name: (addr slice), vars: (addr stack live-var), fn: (addr function), out: (addr handle var), err: (addr buffered-file), ed: (addr exit-descriptor)
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
#
(lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c)) # arg order slightly different; 'fn' is deemphasized
{
# if (out != 0) return
8b/-> *(ebp+0x14) 0/r32/eax
81 7/subop/compare *eax 0/imm32
75/jump-if-!= break/disp8
# if name is one of fn's outputs, return it
(find-in-function-outputs *(ebp+0x10) *(ebp+8) *(ebp+0x14))
8b/-> *(ebp+0x14) 0/r32/eax
81 7/subop/compare *eax 0/imm32
# otherwise abort
0f 84/jump-if-= $lookup-or-define-var:abort/disp32
}
$lookup-or-define-var:end:
# . restore registers
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
$lookup-or-define-var:abort:
(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
find-in-function-outputs: # fn: (addr function), 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 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
# 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 s/eax: (addr array byte) = lookup(v->name)
(lookup *eax *(eax+4)) # Var-name Var-name => eax
# if (s == name) return curr->value
(slice-equal? *(ebp+0xc) %eax) # => eax
3d/compare-eax-and 0/imm32/false
{
74/jump-if-= break/disp8
# var edi = out
57/push-edi
8b/-> *(ebp+0x10) 7/r32/edi
# *out = curr->value
8b/-> *ecx 0/r32/eax
89/<- *edi 0/r32/eax
8b/-> *(ecx+4) 0/r32/eax
89/<- *(edi+4) 0/r32/eax
#
5f/pop-to-edi
eb/jump $find-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
}
b8/copy-to-eax 0/imm32
$find-in-function-outputs:end:
# . restore registers
59/pop-to-ecx
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
# 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
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
# 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-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
(parse-var-with-type %edx %ecx %esi *(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
# eax = f
8b/-> *(ebp+8) 0/r32/eax
# TODO: anything to check in header?
# var body/eax: (addr block) = lookup(f->body)
(lookup *(eax+0x18) *(eax+0x1c)) # Function-body Function-body => eax
(check-mu-block %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10))
$check-mu-function:end:
# . restore registers
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 == "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 == "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 == "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 == "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 == "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
75/jump-if-!= $check-mu-numberlike-arg:end/disp8
$check-mu-numberlike-arg:check-addr:
# if t is an addr and v is dereferenced, return
{
(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
3d/compare-eax-and 0/imm32/false
75/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
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-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-!= $check-mu-numberlike-output:end/disp32
$check-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-!= $check-mu-numberlike-output:end/disp8
$check-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-!= $check-mu-numberlike-output:end/disp8
$check-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-!= $check-mu-numberlike-output:end/disp8
$check-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-!= $check-mu-numberlike-output:end/disp8
$check-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-!= $check-mu-numberlike-output:end/disp8
e9/jump $check-mu-numberlike-output:fail/disp32
$check-mu-numberlike-output: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: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) ": only non-addr scalar args permitted\n")
(flush *(ebp+0x14))
(stop *(ebp+0x18) 1)
# never gets here
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
$check-mu-copy-stmt:end:
# . restore registers
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
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
$check-mu-copy-to-stmt:end:
# . restore registers
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
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
$check-mu-compare-stmt:end:
# . restore registers
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
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
$check-mu-address-stmt:end:
# . restore registers
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
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
# 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
(write-buffered *(ebp+0x10) *(edi+ebx<<2+0xc))
# .
(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 address\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
(write-buffered *(ebp+0x10) *(edi+ebx<<2+0xc))
(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 address\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
$check-mu-length-stmt:end:
# . restore registers
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
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
$check-mu-compute-offset-stmt:end:
# . restore registers
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
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
$check-mu-copy-object-stmt:end:
# . restore registers
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
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
$check-mu-allocate-stmt:end:
# . restore registers
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
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
$check-mu-populate-stmt:end:
# . restore registers
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
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
$check-mu-populate-stream-stmt:end:
# . restore registers
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
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 address\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
$check-mu-write-to-stream-stmt:end:
# . restore registers
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
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
$check-mu-convert-stmt:end:
# . restore registers
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
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-inout-type:
# var v/eax: (addr v) = lookup(inouts->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 (inouts->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
# 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 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 == literal) return true # TODO: more precise
(is-simple-mu-type? *(ebp+0xc) 0) # literal => eax
3d/compare-eax-and 0/imm32/false
b8/copy-to-eax 1/imm32/true
75/jump-if-!= $type-match?:end/disp8
$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
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 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+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+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")
}
3d/compare-eax-and 0/imm32/false # just in case the function call modified flags
{
75/jump-if-!= break/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
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
# otherwise return (stmt->operation starts with "break")
(string-starts-with? %ecx "break") # => 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_87_jump_label/imm32
0x11/imm32/alloc-id _string-loop-if-<=/imm32 0x11/imm32/alloc-id _string_0f_87_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-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
# 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-push-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:
# . 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:
(emit-indent *(ebp+8) *Curr-block-depth)
(write-buffered *(ebp+8) "8f 0/subop/pop %")
(lookup *(ebx+0x18) *(ebx+0x1c)) # Var-register Var-register => eax
(write-buffered *(ebp+8) %eax)
(write-buffered *(ebp+8) Newline)
}
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).
#
# This would be a simple series of pops, if it wasn't for fn outputs, which
# can occur anywhere in the stack.
# So we have to _compact_ the entire array underlying the stack.
#
# We want to allow a fn output register to be written to by locals before the
# output is set.
# So fn outputs can't just be pushed at the start of the function.
#
# We want to allow other locals to shadow a fn output register after the
# output is set.
# So the output can't just always override anything in the stack. Sequence matters.
clean-up-blocks: # vars: (addr stack live-var), until-block-depth: int, fn: (addr function)
# pseudocode:
# to = vars->top (which points outside the stack)
# while true
# if to <= 0
# break
# var v = vars->data[to-1]
# if v.depth < until and !in-function-outputs?(fn, v)
# break
# --to
# from = to
# while true
# if from >= vars->top
# break
# assert(from >= to)
# v = vars->data[from]
# if in-function-outputs?(fn, v)
# if from > to
# vars->data[to] = vars->data[from]
# ++to
# ++from
# vars->top = to
#
# . 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
# ebx = vars
8b/-> *(ebp+8) 3/r32/ebx
# edx = until-block-depth
8b/-> *(ebp+0xc) 2/r32/edx
$clean-up-blocks:phase1:
# var to/edi: int = vars->top
8b/-> *ebx 7/r32/edi
{
$clean-up-blocks:loop1:
# if (to <= 0) break
81 7/subop/compare %edi 0/imm32
7e/jump-if-<= break/disp8
# var v/eax: (addr var) = lookup(vars->data[to-1]->var)
8d/copy-address *(ebx+edi-4) 0/r32/eax # vars + 8 + to - 12
(lookup *eax *(eax+4)) # => eax
# if (v->block-depth >= until-block-depth) continue
39/compare *(eax+0x10) 2/r32/edx # Var-block-depth
{
7d/jump-if->= break/disp8
# if (!in-function-outputs?(fn, v)) break
(in-function-outputs? *(ebp+0x10) %eax) # => eax
3d/compare-eax-and 0/imm32/false
74/jump-if-= $clean-up-blocks:phase2/disp8
}
$clean-up-blocks:loop1-continue:
# --to
81 5/subop/subtract %edi 0xc/imm32
#
eb/jump loop/disp8
}
$clean-up-blocks:phase2:
# var from/esi: int = to
89/<- %esi 7/r32/edi
{
$clean-up-blocks:loop2:
# if (from >= vars->top) break
3b/compare 6/r32/esi *ebx
7d/jump-if->= break/disp8
# var v/eax: (addr var) = lookup(vars->data[from]->var)
8d/copy-address *(ebx+esi+8) 0/r32/eax
(lookup *eax *(eax+4)) # => eax
# if !in-function-outputs?(fn, v) continue
(in-function-outputs? *(ebp+0x10) %eax) # => eax
3d/compare-eax-and 0/imm32/false
74/jump-if-= $clean-up-blocks:loop2-continue/disp8
# invariant: from >= to
# if (from > to) vars->data[to] = vars->data[from]
{
39/compare %esi 7/r32/edi
7e/jump-if-<= break/disp8
56/push-esi
57/push-edi
# . var from/esi: (addr byte) = &vars->data[from]
8d/copy-address *(ebx+esi+8) 6/r32/esi
# . var to/edi: (addr byte) = &vars->data[to]
8d/copy-address *(ebx+edi+8) 7/r32/edi
# .
8b/-> *esi 0/r32/eax
89/<- *edi 0/r32/eax
8b/-> *(esi+4) 0/r32/eax
89/<- *(edi+4) 0/r32/eax
8b/-> *(esi+8) 0/r32/eax
89/<- *(edi+8) 0/r32/eax
5f/pop-to-edi
5e/pop-to-esi
}
# ++to
81 0/subop/add %edi 0xc/imm32
$clean-up-blocks:loop2-continue:
# ++from
81 0/subop/add %esi 0xc/imm32
#
eb/jump loop/disp8
}
89/<- *ebx 7/r32/edi
$clean-up-blocks:end:
# . 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
in-function-outputs?: # fn: (addr function), target: (addr var) -> 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) 1/r32/ecx
(lookup *(ecx+0x10) *(ecx+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
# if (v == target) return true
39/compare *(ebp+0xc) 0/r32/eax
b8/copy-to-eax 1/imm32/true
74/jump-if-= $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
}
b8/copy-to-eax 0/imm32
$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), 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
# array size
{
# if (!string-equal?(stmt->operation, "length")) break
(string-equal? %ecx "length") # => eax
3d/compare-eax-and 0/imm32
0f 84/jump-if-= break/disp32
(translate-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
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
0f 84/jump-if-= break/disp32
(translate-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
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
0f 84/jump-if-= break/disp32
(translate-mu-compute-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
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
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
0f 84/jump-if-= break/disp32
(translate-mu-allocate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
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
0f 84/jump-if-= break/disp32
(translate-mu-copy-object-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
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
0f 84/jump-if-= break/disp32
(translate-mu-populate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
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
0f 84/jump-if-= break/disp32
(translate-mu-populate-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
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
0f 84/jump-if-= break/disp32
(translate-mu-read-from-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
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
0f 84/jump-if-= break/disp32
(translate-mu-write-to-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
e9/jump $emit-subx-stmt:end/disp32
}
# - 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
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-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
51/push-ecx
# ecx = stmt
8b/-> *(ebp+0xc) 1/r32/ecx
# var base/ecx: (addr var) = stmt->inouts[0]
(lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax
(lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax
89/<- %ecx 0/r32/eax
# if (var->register) do one thing
{
81 7/subop/compare *(ecx+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+0x10) *(ebp+0x14))
eb/jump $translate-mu-index-stmt:end/disp8
}
# if (var->offset) do a different thing
{
81 7/subop/compare *(ecx+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+0x10) *(ebp+0x14))
eb/jump $translate-mu-index-stmt:end/disp8
}
$translate-mu-index-stmt:end:
# . restore registers
59/pop-to-ecx
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
$translate-mu-index-stmt-with-array:error1:
(write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input must either lie in a register or be a literal\n")
(flush *(ebp+0x10))
(stop *(ebp+0x14) 1)
# never gets here
$translate-mu-index-stmt-with-array:error2:
(write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input when in a register must be an int or offset\n")
(flush *(ebp+0x10))
(stop *(ebp+0x14) 1)
# never gets here
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))
# TODO: ensure 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-with-array: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-with-array: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-with-array: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-with-array: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)
(lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => 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-copy-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
1/imm32/xm32-is-first-inout
2/imm32/x32-is-second-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-left
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)
}
$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) # => 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-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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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