13372 lines
525 KiB
Plaintext
13372 lines
525 KiB
Plaintext
# 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
|
|
|
|
# == 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
|
|
# heap allocations (planned name: 'handle')
|
|
# user-defined types: 'type' for structs, 'choice' for unions
|
|
# short-lived 'address' type for efficiently writing inside nested structs
|
|
#
|
|
# We don't have 'handle' types yet, but we try to distinguish 'ref', 'handle'
|
|
# and 'address' in comments. Their definitions are in layer 50, but really you
|
|
# can ignore the distinctions on a first reading of this program.
|
|
#
|
|
# 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 tree type-id)
|
|
#
|
|
# 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 tree type-id)
|
|
#
|
|
# A variable defined in a register contains:
|
|
# tag: 3
|
|
# name: (handle array byte)
|
|
# type: (handle tree type-id)
|
|
# 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 tree type-id)
|
|
# 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, ...
|
|
# =>
|
|
# (subx-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 (singleton linked list)
|
|
# subx-name: (handle array byte)
|
|
|
|
# == 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-disp32: enum arg-location
|
|
# output-is-write-only: boolean
|
|
# 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
|
|
|
|
# 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-disp32: # enum arg-location -- only for branches
|
|
0x2c/imm32
|
|
Primitive-output-is-write-only: # boolean
|
|
0x30/imm32
|
|
Primitive-next: # (handle function)
|
|
0x34/imm32
|
|
Primitive-size: # (addr int)
|
|
0x3c/imm32/60
|
|
|
|
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 tree type-id)
|
|
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
|
|
|
|
Any-register: # (handle array byte)
|
|
# alloc-id
|
|
0x11/imm32
|
|
# size
|
|
1/imm32
|
|
# data
|
|
2a/asterisk
|
|
|
|
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
|
|
|
|
# Types are expressed as trees (s-expressions) of type-ids (ints).
|
|
# However, there's no need for singletons, so we can assume (int) == int
|
|
# - if x->right == nil, x is an atom
|
|
# - x->left contains either a pointer to a pair, or an atomic type-id directly.
|
|
|
|
Tree-is-atom: # boolean
|
|
0/imm32
|
|
# if left-is-atom?
|
|
Tree-value: # type-id
|
|
4/imm32
|
|
# unless left-is-atom?
|
|
Tree-left: # (addr tree type-id)
|
|
4/imm32
|
|
Tree-right: # (addr tree type-id)
|
|
0xc/imm32
|
|
#
|
|
Tree-size: # (addr int)
|
|
0x14/imm32
|
|
|
|
# Types
|
|
|
|
# TODO: heap allocations here can't be reclaimed
|
|
Type-id: # (stream (addr array byte))
|
|
0x1c/imm32/write
|
|
0/imm32/read
|
|
0x100/imm32/size
|
|
# data
|
|
"literal"/imm32 # 0
|
|
"int"/imm32 # 1
|
|
"addr"/imm32 # 2
|
|
"array"/imm32 # 3
|
|
"handle"/imm32 # 4
|
|
"boolean"/imm32 # 5
|
|
"constant"/imm32 # 6: like a literal, but replaced with its value in Var-offset
|
|
"offset"/imm32 # 7: (offset T) is guaranteed to be a 32-bit multiple of size-of(T)
|
|
0/imm32
|
|
# 0x20
|
|
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
|
|
0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
|
|
|
|
# == 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)
|
|
(flush Stdout)
|
|
# syscall(exit, 0)
|
|
bb/copy-to-ebx 0/imm32
|
|
$mu-main:end:
|
|
b8/copy-to-eax 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
|
|
convert-mu: # in: (addr buffered-file), out: (addr buffered-file)
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
# initialize global data structures
|
|
c7 0/subop/copy *Next-block-index 1/imm32
|
|
c7 0/subop/copy *Type-id 0x1c/imm32 # 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
|
|
#
|
|
(parse-mu *(ebp+8))
|
|
(populate-mu-type-sizes)
|
|
(check-mu-types)
|
|
(emit-subx *(ebp+0xc))
|
|
$convert-mu:end:
|
|
# . 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)
|
|
(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)
|
|
(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)
|
|
(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)
|
|
(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)
|
|
(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)
|
|
(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)
|
|
(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)
|
|
(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)
|
|
(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)
|
|
(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-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)
|
|
(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-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)
|
|
(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)
|
|
(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-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)
|
|
(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-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)
|
|
(flush _test-output-buffered-file)
|
|
#? # dump _test-output-stream {{{
|
|
#? (write 2 "^")
|
|
#? (write-stream 2 _test-output-stream)
|
|
#? (write 2 "$\n")
|
|
#? (rewind-stream _test-output-stream)
|
|
#? # }}}
|
|
# check output
|
|
(check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-var-dereferenced/0")
|
|
(check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-local-var-dereferenced/1")
|
|
(check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-local-var-dereferenced/2")
|
|
(check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-local-var-dereferenced/3")
|
|
(check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-local-var-dereferenced/4")
|
|
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-local-var-dereferenced/5")
|
|
(check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-function-with-local-var-dereferenced/6")
|
|
(check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 0/imm32" "F - test-convert-function-with-local-var-dereferenced/7")
|
|
(check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *ecx" "F - test-convert-function-with-local-var-dereferenced/8")
|
|
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-dereferenced/9")
|
|
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-local-var-dereferenced/10")
|
|
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-local-var-dereferenced/11")
|
|
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-local-var-dereferenced/12")
|
|
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-local-var-dereferenced/13")
|
|
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-local-var-dereferenced/14")
|
|
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-local-var-dereferenced/15")
|
|
# . epilogue
|
|
89/<- %esp 5/r32/ebp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-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)
|
|
(flush _test-output-buffered-file)
|
|
#? # dump _test-output-stream {{{
|
|
#? (write 2 "^")
|
|
#? (write-stream 2 _test-output-stream)
|
|
#? (write 2 "$\n")
|
|
#? (rewind-stream _test-output-stream)
|
|
#? # }}}
|
|
# check output
|
|
(check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-compare-register-with-literal/0")
|
|
(check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-compare-register-with-literal/1")
|
|
(check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-compare-register-with-literal/2")
|
|
(check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-compare-register-with-literal/3")
|
|
(check-next-stream-line-equal _test-output-stream " {" "F - test-convert-compare-register-with-literal/4")
|
|
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-compare-register-with-literal/5")
|
|
(check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-compare-register-with-literal/6")
|
|
(check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 0/imm32" "F - test-convert-compare-register-with-literal/7")
|
|
(check-next-stream-line-equal _test-output-stream " 81 7/subop/compare %ecx 0/imm32" "F - test-convert-compare-register-with-literal/8")
|
|
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
|
|
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-compare-register-with-literal/10")
|
|
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-compare-register-with-literal/11")
|
|
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-compare-register-with-literal/12")
|
|
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-compare-register-with-literal/13")
|
|
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-compare-register-with-literal/14")
|
|
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-compare-register-with-literal/15")
|
|
# . epilogue
|
|
89/<- %esp 5/r32/ebp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-convert-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)
|
|
(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-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)
|
|
(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-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)
|
|
(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)
|
|
(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)
|
|
(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/21")
|
|
# . 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)
|
|
(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
|
|
|
|
_pending-test-local-clobbered-by-output:
|
|
# also doesn't spill
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
# setup
|
|
(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)
|
|
(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-output/0")
|
|
(check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-local-clobbered-by-output/1")
|
|
(check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-local-clobbered-by-output/2")
|
|
(check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-local-clobbered-by-output/3")
|
|
(check-next-stream-line-equal _test-output-stream " {" "F - test-local-clobbered-by-output/4")
|
|
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-local-clobbered-by-output/5")
|
|
(check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 4/imm32" "F - test-local-clobbered-by-output/6")
|
|
(check-next-stream-line-equal _test-output-stream " 89/<- %ecx 0x00000001/r32" "F - test-local-clobbered-by-output/7")
|
|
(check-next-stream-line-equal _test-output-stream " }" "F - test-local-clobbered-by-output/8")
|
|
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-local-clobbered-by-output/9")
|
|
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-local-clobbered-by-output/10")
|
|
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-local-clobbered-by-output/11")
|
|
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-local-clobbered-by-output/12")
|
|
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-local-clobbered-by-output/13")
|
|
# . 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)
|
|
(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 " 0f 8d/jump-if->= break/disp32" "F - test-convert-function-with-branches-in-block/8")
|
|
(check-next-stream-line-equal _test-output-stream " 0f 82/jump-if-addr< loop/disp32" "F - test-convert-function-with-branches-in-block/9")
|
|
(check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0x00000008)" "F - test-convert-function-with-branches-in-block/10")
|
|
(check-next-stream-line-equal _test-output-stream " e9/jump loop/disp32" "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 "$foo:0x00000002:break:" "F - test-convert-function-with-branches-in-block/13")
|
|
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-in-block/14")
|
|
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-branches-in-block/15")
|
|
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-branches-in-block/16")
|
|
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-branches-in-block/17")
|
|
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-branches-in-block/18")
|
|
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-branches-in-block/19")
|
|
# . 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)
|
|
(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 " 0f 8d/jump-if->= $bar:break/disp32" "F - test-convert-function-with-branches-in-named-block/8")
|
|
(check-next-stream-line-equal _test-output-stream " 0f 82/jump-if-addr< $bar:loop/disp32" "F - test-convert-function-with-branches-in-named-block/9")
|
|
(check-next-stream-line-equal _test-output-stream " ff 0/subop/increment *(ebp+0x00000008)" "F - test-convert-function-with-branches-in-named-block/10")
|
|
(check-next-stream-line-equal _test-output-stream " e9/jump loop/disp32" "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 "$bar:break:" "F - test-convert-function-with-branches-in-named-block/13")
|
|
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-branches-in-named-block/14")
|
|
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-branches-in-named-block/15")
|
|
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-branches-in-named-block/16")
|
|
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-branches-in-named-block/17")
|
|
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-branches-in-named-block/18")
|
|
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-branches-in-named-block/19")
|
|
# . 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)
|
|
(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)
|
|
(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)
|
|
(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)
|
|
(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)
|
|
(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)
|
|
(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)
|
|
(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-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)
|
|
(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)
|
|
(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)
|
|
(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)
|
|
(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-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)
|
|
(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-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)
|
|
(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/9")
|
|
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-length-of-array/11")
|
|
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-length-of-array/12")
|
|
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-length-of-array/13")
|
|
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-length-of-array/14")
|
|
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-length-of-array/15")
|
|
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-length-of-array/16")
|
|
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-length-of-array/17")
|
|
# . 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)
|
|
(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 " 8f 0/subop/pop %eax" "F - test-convert-length-of-array-on-stack/10")
|
|
(check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000010/imm32" "F - test-convert-length-of-array-on-stack/11")
|
|
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-length-of-array-on-stack/12")
|
|
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-length-of-array-on-stack/13")
|
|
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-length-of-array-on-stack/14")
|
|
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-length-of-array-on-stack/15")
|
|
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-length-of-array-on-stack/16")
|
|
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-length-of-array-on-stack/17")
|
|
# . epilogue
|
|
89/<- %esp 5/r32/ebp
|
|
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)
|
|
(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/11")
|
|
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array/13")
|
|
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array/14")
|
|
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array/15")
|
|
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array/16")
|
|
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array/17")
|
|
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array/18")
|
|
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array/19")
|
|
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array/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)
|
|
(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-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)
|
|
(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)
|
|
(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-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)
|
|
(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-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)
|
|
(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-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)
|
|
(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-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)
|
|
(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-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)
|
|
(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)
|
|
(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)
|
|
(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 " 89/<- %ecx 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-of-type-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: 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)
|
|
(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-of-type-on-stack/0")
|
|
(check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-get-of-type-on-stack/1")
|
|
(check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-get-of-type-on-stack/2")
|
|
(check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-get-of-type-on-stack/3")
|
|
(check-next-stream-line-equal _test-output-stream " {" "F - test-convert-get-of-type-on-stack/4")
|
|
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-get-of-type-on-stack/5")
|
|
# var a
|
|
(check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-get-of-type-on-stack/6")
|
|
(check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-get-of-type-on-stack/7")
|
|
# var c
|
|
(check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-get-of-type-on-stack/8")
|
|
# get
|
|
(check-next-stream-line-equal _test-output-stream " 8d/copy-address *(ebp+0xfffffffc) 0x00000001/r32" "F - test-convert-get-of-type-on-stack/9")
|
|
# reclaim c
|
|
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-get-of-type-on-stack/10")
|
|
# reclaim a
|
|
(check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000008/imm32" "F - test-convert-get-of-type-on-stack/11")
|
|
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-get-of-type-on-stack/12")
|
|
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-get-of-type-on-stack/13")
|
|
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-get-of-type-on-stack/14")
|
|
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-get-of-type-on-stack/15")
|
|
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-get-of-type-on-stack/16")
|
|
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-get-of-type-on-stack/17")
|
|
# . epilogue
|
|
89/<- %esp 5/r32/ebp
|
|
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 int) <- index arr, idx\n")
|
|
(write _test-input-stream "}\n")
|
|
# convert
|
|
(convert-mu _test-input-buffered-file _test-output-buffered-file)
|
|
(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
|
|
|
|
#######################################################
|
|
# Parsing
|
|
#######################################################
|
|
|
|
parse-mu: # in: (addr buffered-file)
|
|
# pseudocode
|
|
# var curr-function: (addr handle function) = Program->functions
|
|
# 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 (handle 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, "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
|
|
# . 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 (handle var) 256)
|
|
81 5/subop/subtract %esp 0x800/imm32
|
|
68/push 0x800/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
|
|
(clear-stack %ebx)
|
|
(populate-mu-function-header %ecx %eax %ebx)
|
|
(populate-mu-function-body *(ebp+8) %eax %ebx)
|
|
# *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+0x28) 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, "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 '{'
|
|
(populate-mu-type *(ebp+8) %eax) # => eax
|
|
# 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 0x630/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-mu:error1:
|
|
# error("unexpected top-level command: " word-slice "\n")
|
|
(write-buffered Stderr "unexpected top-level command: ")
|
|
(write-slice-buffered Stderr %edx)
|
|
(write-buffered Stderr "\n")
|
|
(flush Stderr)
|
|
# . syscall(exit, 1)
|
|
bb/copy-to-ebx 1/imm32
|
|
b8/copy-to-eax 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# never gets here
|
|
|
|
$parse-mu:error2:
|
|
# error(vars->top " vars not reclaimed after fn '" new-function->name "'\n")
|
|
(print-int32-buffered Stderr *ebx)
|
|
(write-buffered Stderr " vars not reclaimed after fn '")
|
|
(write-slice-buffered Stderr *eax) # Function-name
|
|
(write-buffered Stderr "'\n")
|
|
(flush Stderr)
|
|
# . syscall(exit, 1)
|
|
bb/copy-to-ebx 1/imm32
|
|
b8/copy-to-eax 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# 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 {
|
|
populate-mu-function-header: # first-line: (addr stream byte), out: (addr function), vars: (addr stack (handle var))
|
|
# pseudocode:
|
|
# var name: slice
|
|
# next-mu-token(first-line, name)
|
|
# assert(name not in '{' '}' '->')
|
|
# out->name = slice-to-string(name)
|
|
# ## inouts
|
|
# while true
|
|
# ## name
|
|
# name = next-mu-token(first-line)
|
|
# if (name == '{') goto done
|
|
# if (name == '->') break
|
|
# assert(name != '}')
|
|
# var v: (handle var) = parse-var-with-type(name, first-line)
|
|
# assert(v->register == null)
|
|
# # v->block-depth is implicitly 0
|
|
# out->inouts = append(v, out->inouts)
|
|
# push(vars, v)
|
|
# ## outputs
|
|
# while true
|
|
# ## name
|
|
# name = next-mu-token(first-line)
|
|
# assert(name not in '{' '}' '->')
|
|
# var v: (handle var) = parse-var-with-type(name, 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
|
|
# TODO: error if name starts with 'break' or 'loop'
|
|
# 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 (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)
|
|
# 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)
|
|
(push *(ebp+0x10) *ebx)
|
|
(push *(ebp+0x10) *(ebx+4))
|
|
#
|
|
e9/jump loop/disp32
|
|
}
|
|
# save function outputs
|
|
{
|
|
$populate-mu-function-header:check-for-out:
|
|
(next-mu-token *(ebp+8) %ecx)
|
|
# 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)
|
|
# 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 Stderr "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '")
|
|
(flush Stderr)
|
|
(rewind-stream *(ebp+8))
|
|
(write-stream 2 *(ebp+8))
|
|
(write-buffered Stderr "'\n")
|
|
(flush Stderr)
|
|
# . syscall(exit, 1)
|
|
bb/copy-to-ebx 1/imm32
|
|
b8/copy-to-eax 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# never gets here
|
|
|
|
$populate-mu-function-header:error2:
|
|
# error("function input '" var "' cannot be in a register")
|
|
(write-buffered Stderr "function input '")
|
|
(write-buffered Stderr *ebx) # Var-name
|
|
(write-buffered Stderr "' cannot be in a register")
|
|
(flush Stderr)
|
|
# . syscall(exit, 1)
|
|
bb/copy-to-ebx 1/imm32
|
|
b8/copy-to-eax 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# never gets here
|
|
|
|
$populate-mu-function-header:error3:
|
|
# error("function input '" var "' must be in a register")
|
|
(write-buffered Stderr "function input '")
|
|
(lookup *ebx *(ebx+4)) # => eax
|
|
(lookup *eax *(eax+4)) # Var-name Var-name => eax
|
|
(write-buffered Stderr %eax)
|
|
(write-buffered Stderr "' must be in a register, in instruction '")
|
|
(flush Stderr)
|
|
(rewind-stream *(ebp+8))
|
|
(write-stream 2 *(ebp+8))
|
|
(write-buffered Stderr "'\n")
|
|
(flush Stderr)
|
|
# . syscall(exit, 1)
|
|
bb/copy-to-ebx 1/imm32
|
|
b8/copy-to-eax 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# never gets here
|
|
|
|
test-function-header-with-arg:
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
# setup
|
|
(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 (handle var) 16)
|
|
81 5/subop/subtract %esp 0x80/imm32
|
|
68/push 0x80/imm32/size
|
|
68/push 0/imm32/top
|
|
89/<- %ebx 4/r32/esp
|
|
# convert
|
|
(populate-mu-function-header _test-input-stream %ecx %ebx)
|
|
# 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") # Tree-is-atom
|
|
(check-ints-equal *(eax+4) 1 "F - test-function-header-with-arg/inout:0/type:1") # Tree-value
|
|
(check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-arg/inout:0/type:2") # 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
|
|
(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 (handle var) 16)
|
|
81 5/subop/subtract %esp 0x80/imm32
|
|
68/push 0x80/imm32/size
|
|
68/push 0/imm32/top
|
|
89/<- %ebx 4/r32/esp
|
|
# convert
|
|
(populate-mu-function-header _test-input-stream %ecx %ebx)
|
|
# 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") # Tree-is-atom
|
|
(check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:0/type:1") # Tree-value
|
|
(check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:0/type:2") # 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") # Tree-is-atom
|
|
(check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:1/type:1") # Tree-value
|
|
(check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:1/type:2") # 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") # Tree-is-atom
|
|
(check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:2/type:1") # Tree-value
|
|
(check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:2/type:2") # 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
|
|
(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 (handle var) 16)
|
|
81 5/subop/subtract %esp 0x80/imm32
|
|
68/push 0x80/imm32/size
|
|
68/push 0/imm32/top
|
|
89/<- %ebx 4/r32/esp
|
|
# convert
|
|
(populate-mu-function-header _test-input-stream %ecx %ebx)
|
|
# 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") # Tree-is-atom
|
|
(check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1") # Tree-value
|
|
(check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:2") # 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") # Tree-is-atom
|
|
(check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1") # Tree-value
|
|
(check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:2") # 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") # Tree-is-atom
|
|
(check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1") # Tree-value
|
|
(check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:2") # 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") # Tree-is-atom
|
|
(check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1") # Tree-value
|
|
(check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:2") # 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") # Tree-is-atom
|
|
(check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1") # Tree-value
|
|
(check-ints-equal *(eax+0c) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:2") # 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)
|
|
# 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 tree type-id) = 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)
|
|
$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 Stderr "var should have form 'name: type' in '")
|
|
(flush Stderr)
|
|
(rewind-stream *(ebp+0xc))
|
|
(write-stream 2 *(ebp+0xc))
|
|
(write-buffered Stderr "'\n")
|
|
(flush Stderr)
|
|
# . syscall(exit, 1)
|
|
bb/copy-to-ebx 1/imm32
|
|
b8/copy-to-eax 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# never gets here
|
|
|
|
parse-type: # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle tree type-id)
|
|
# pseudocode:
|
|
# var s: slice = next-mu-token(in)
|
|
# assert s != ""
|
|
# assert s != "->"
|
|
# assert s != "{"
|
|
# assert s != "}"
|
|
# if s == ")"
|
|
# return
|
|
# out = allocate(Tree)
|
|
# if s != "("
|
|
# HACK: if s is an int, parse and return it
|
|
# out->left-is-atom? = true
|
|
# 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) *Tree-size *(ebp+0x10))
|
|
# var out-addr/edx: (addr tree type-id) = 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
|
|
75/jump-if-!= break/disp8
|
|
# EGREGIOUS HACK for static array sizes: if s is a number, parse it
|
|
{
|
|
$parse-type:check-for-int:
|
|
(is-hex-int? %ecx) # => eax
|
|
3d/compare-eax-and 0/imm32/false
|
|
74/jump-if-= break/disp8
|
|
$parse-type:int:
|
|
(parse-hex-int-from-slice %ecx) # => eax
|
|
89/<- *(edx+4) 0/r32/eax # Tree-value
|
|
e9/jump $parse-type:end/disp32
|
|
}
|
|
$parse-type:atom:
|
|
# out->left-is-atom? = true
|
|
c7 0/subop/copy *edx 1/imm32/true # Tree-is-atom
|
|
# out->value = pos-or-insert-slice(Type-id, s)
|
|
(pos-or-insert-slice Type-id %ecx) # => eax
|
|
89/<- *(edx+4) 0/r32/eax # 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 # Tree-left
|
|
(parse-type *(ebp+8) *(ebp+0xc) %eax)
|
|
# out->right = parse-type-tree(ad, in)
|
|
8d/copy-address *(edx+0xc) 0/r32/eax # Tree-right
|
|
(parse-type-tree *(ebp+8) *(ebp+0xc) %eax)
|
|
$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 Stderr "unexpected token when parsing type: '")
|
|
(write-slice-buffered Stderr %ecx)
|
|
(write-buffered Stderr "'\n")
|
|
(flush Stderr)
|
|
# . syscall(exit, 1)
|
|
bb/copy-to-ebx 1/imm32
|
|
b8/copy-to-eax 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# never gets here
|
|
|
|
parse-type-tree: # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle tree type-id)
|
|
# pseudocode:
|
|
# var tmp: (handle tree type-id) = parse-type(ad, in)
|
|
# if tmp == 0
|
|
# return 0
|
|
# out = allocate(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 tree type-id)
|
|
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)
|
|
# 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) *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 # Tree-left
|
|
8b/-> *(ecx+4) 0/r32/eax
|
|
89/<- *(edx+8) 0/r32/eax # Tree-left
|
|
# out->right = parse-type-tree(ad, in)
|
|
8d/copy-address *(edx+0xc) 0/r32/eax # Tree-right
|
|
(parse-type-tree *(ebp+8) *(ebp+0xc) %eax)
|
|
$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 " ")
|
|
#? (print-int32-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 "=> ")
|
|
#? (print-int32-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
|
|
# (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)
|
|
# 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") # Tree-is-atom
|
|
(check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type/type:1") # Tree-value
|
|
(check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type/type:2") # 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
|
|
# (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)
|
|
# 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") # Tree-is-atom
|
|
(check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type-and-register/type:1") # Tree-left
|
|
(check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type-and-register/type:2") # 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
|
|
# (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)
|
|
# 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") # Tree-is-atom
|
|
(check-ints-equal *(eax+4) 1 "F - test-parse-var-with-trailing-characters/type:1") # Tree-left
|
|
(check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-trailing-characters/type:1") # 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
|
|
# (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)
|
|
# 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") # Tree-is-atom
|
|
(check-ints-equal *(eax+4) 1 "F - test-parse-var-with-register-and-trailing-characters/type:1") # Tree-left
|
|
(check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-register-and-trailing-characters/type:2") # 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
|
|
# (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)
|
|
# 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 tree type-id) = 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") # Tree-is-atom
|
|
# type->left == atom(addr)
|
|
(lookup *(edx+4) *(edx+8)) # Tree-left Tree-left => eax
|
|
(check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:1") # Tree-is-atom
|
|
(check-ints-equal *(eax+4) 2 "F - test-parse-var-with-compound-type/type:2") # Tree-value
|
|
# type->right->left == atom(int)
|
|
(lookup *(edx+0xc) *(edx+0x10)) # Tree-right Tree-right => eax
|
|
(lookup *(eax+4) *(eax+8)) # Tree-left Tree-left => eax
|
|
(check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:3") # Tree-is-atom
|
|
(check-ints-equal *(eax+4) 1 "F - test-parse-var-with-compound-type/type:4") # Tree-value
|
|
# type->right->right == null
|
|
(check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-compound-type/type:5") # 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 (handle var))
|
|
# . 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
|
|
# 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)
|
|
$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 (handle var)), fn: (addr function), out: (addr handle block)
|
|
# 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)
|
|
# 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)
|
|
# 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
|
|
{
|
|
$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)
|
|
#? (flush Stderr)
|
|
# if (line->write == 0) break
|
|
81 7/subop/compare *ecx 0/imm32
|
|
0f 84/jump-if-= break/disp32
|
|
# 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)
|
|
(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)
|
|
(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)
|
|
(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)
|
|
(append-to-block Heap %edi *eax *(eax+4))
|
|
# reclaim tmp
|
|
81 0/subop/add %esp 8/imm32
|
|
#
|
|
e9/jump loop/disp32
|
|
} # end line loop
|
|
# pop(vars)
|
|
(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 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
|
|
b8/copy-to-eax 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# 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
|
|
8b/-> *eax 0/r32/eax # Function-name
|
|
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
|
|
8b/-> *eax 0/r32/eax # Function-name
|
|
# construct result using Next-block-index (and increment it)
|
|
(write %edx "$")
|
|
(write %edx %eax)
|
|
(write %edx ":")
|
|
(print-int32 %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))
|
|
$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
|
|
|
|
== data
|
|
|
|
# Global state added to each var record when parsing a function
|
|
Next-block-index: # (addr int)
|
|
1/imm32
|
|
|
|
== code
|
|
|
|
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
|
|
b8/copy-to-eax 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# 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 (handle var)), fn: (addr function), out: (addr handle stmt)
|
|
# pseudocode:
|
|
# var v: (handle var)
|
|
# new-literal(name, v)
|
|
# push(vars, v)
|
|
# 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))
|
|
#
|
|
(parse-mu-block *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18))
|
|
# pop v off vars
|
|
(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 (handle var)), out: (addr handle stmt)
|
|
# . 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+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)
|
|
#
|
|
(push *(ebp+0xc) *edx)
|
|
(push *(ebp+0xc) *(edx+4))
|
|
# either v has no register and there's no more to this line
|
|
(lookup *edx *(edx+4)) # => eax
|
|
8b/-> *(eax+0x18) 0/r32/eax # Var-register
|
|
3d/compare-eax-and 0/imm32
|
|
{
|
|
75/jump-if-!= break/disp8
|
|
# TODO: ensure that there's nothing else on this line
|
|
(new-var-def Heap *edx *(edx+4) %edi)
|
|
eb/jump $parse-mu-var-def:end/disp8
|
|
}
|
|
# or v has a register and there's more to this line
|
|
{
|
|
74/jump-if-= break/disp8
|
|
# ensure that the next word is '<-'
|
|
(next-mu-token *(ebp+8) %ecx)
|
|
(slice-equal? %ecx "<-") # => eax
|
|
3d/compare-eax-and 0/imm32/false
|
|
74/jump-if-= $parse-mu-var-def:abort/disp8
|
|
#
|
|
(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))
|
|
}
|
|
$parse-mu-var-def:end:
|
|
# . reclaim locals
|
|
81 0/subop/add %esp 0x10/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
|
|
|
|
$parse-mu-var-def:abort:
|
|
(rewind-stream *(ebp+8))
|
|
# error("register variable requires a valid instruction to initialize but got '" line "'\n")
|
|
(write-buffered Stderr "register variable requires a valid instruction to initialize but got '")
|
|
(flush Stderr)
|
|
(write-stream 2 *(ebp+8))
|
|
(write-buffered Stderr "'\n")
|
|
(flush Stderr)
|
|
# . syscall(exit, 1)
|
|
bb/copy-to-ebx 1/imm32
|
|
b8/copy-to-eax 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# never gets here
|
|
|
|
test-parse-mu-var-def:
|
|
# 'var n: int'
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
# setup
|
|
(clear-stream _test-input-stream)
|
|
(write _test-input-stream "n: int\n") # caller has consumed the 'var'
|
|
# 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 0x80/imm32
|
|
68/push 0x80/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)
|
|
# 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->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") # Tree-is-atom
|
|
(check-ints-equal *(eax+4) 1 "F - test-parse-mu-var-def/var-type:1") # Tree-value
|
|
(check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-var-def/var-type:2") # 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
|
|
(clear-stream _test-input-stream)
|
|
(write _test-input-stream "n/eax: int <- copy 0\n") # caller has consumed the 'var'
|
|
# 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 0x80/imm32
|
|
68/push 0x80/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)
|
|
# 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->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") # Tree-is-atom
|
|
(check-ints-equal *(eax+4) 1 "F - test-parse-mu-reg-var-def/output-type:1") # Tree-value
|
|
(check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-reg-var-def/output-type:2") # Tree-right
|
|
# . epilogue
|
|
89/<- %esp 5/r32/ebp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
parse-mu-stmt: # line: (addr stream byte), vars: (addr stack (handle var)), fn: (addr function), out: (addr handle stmt)
|
|
# 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-or-define-var(name, vars, fn) # regular stmts may define vars in fn outputs
|
|
# out-addr->outputs = append(v, out-addr->outputs)
|
|
# add-operation-and-inputs-to-stmt(out-addr, line, vars)
|
|
#
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
# . save registers
|
|
50/push-eax
|
|
51/push-ecx
|
|
52/push-edx
|
|
53/push-ebx
|
|
57/push-edi
|
|
# var name/ecx: slice
|
|
68/push 0/imm32/end
|
|
68/push 0/imm32/start
|
|
89/<- %ecx 4/r32/esp
|
|
# var is-deref?/edx: boolean = false
|
|
ba/copy-to-edx 0/imm32/false
|
|
# var v: (handle var)
|
|
68/push 0/imm32
|
|
68/push 0/imm32
|
|
89/<- %ebx 4/r32/esp
|
|
#
|
|
(allocate Heap *Stmt-size *(ebp+0x14))
|
|
# var out-addr/edi: (addr stmt) = lookup(*out)
|
|
8b/-> *(ebp+0x14) 7/r32/edi
|
|
(lookup *edi *(edi+4)) # => eax
|
|
89/<- %edi 0/r32/eax
|
|
# out-addr->tag = 1/stmt
|
|
c7 0/subop/copy *edi 1/imm32/stmt1 # Stmt-tag
|
|
{
|
|
(stmt-has-outputs? *(ebp+8))
|
|
3d/compare-eax-and 0/imm32/false
|
|
0f 84/jump-if-= break/disp32
|
|
{
|
|
$parse-mu-stmt:read-outputs:
|
|
# name = next-mu-token(line)
|
|
(next-mu-token *(ebp+8) %ecx)
|
|
# if slice-empty?(word-slice) break
|
|
(slice-empty? %ecx) # => eax
|
|
3d/compare-eax-and 0/imm32/false
|
|
0f 85/jump-if-!= break/disp32
|
|
# if (name == "<-") break
|
|
(slice-equal? %ecx "<-") # => eax
|
|
3d/compare-eax-and 0/imm32/false
|
|
0f 85/jump-if-!= break/disp32
|
|
# 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-or-define-var %ecx *(ebp+0xc) *(ebp+0x10) %ebx)
|
|
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))
|
|
$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 Stderr "invalid identifier '")
|
|
(write-slice-buffered Stderr %ecx)
|
|
(write-buffered Stderr "'\n")
|
|
(flush Stderr)
|
|
# . syscall(exit, 1)
|
|
bb/copy-to-ebx 1/imm32
|
|
b8/copy-to-eax 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# never gets here
|
|
|
|
add-operation-and-inputs-to-stmt: # stmt: (addr stmt), line: (addr stream byte), vars: (addr stack (handle var))
|
|
# 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
|
|
81 7/subop/compare *(edi+8) 0/imm32 # Stmt1-inouts or Regvardef-inouts
|
|
74/jump-if-= break/disp8
|
|
(lookup-or-create-constant *(edi+8) %ecx) # Stmt1-inouts => eax
|
|
#? (write-buffered Stderr "creating new output var ")
|
|
#? (print-int32-buffered Stderr %eax)
|
|
#? (write-buffered Stderr " for field called ")
|
|
#? (write-slice-buffered Stderr %ecx)
|
|
#? (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)
|
|
$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("invalid statement '" line "'\n")
|
|
(rewind-stream *(ebp+8))
|
|
(write-buffered Stderr "invalid identifier '")
|
|
(flush Stderr)
|
|
(write-stream 2 *(ebp+8))
|
|
(write-buffered Stderr "'\n")
|
|
(flush Stderr)
|
|
# . syscall(exit, 1)
|
|
bb/copy-to-ebx 1/imm32
|
|
b8/copy-to-eax 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# 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 (handle var)), out: (addr handle var)
|
|
# . 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) return new var(name)
|
|
{
|
|
(is-decimal-digit? %ecx) # => eax
|
|
3d/compare-eax-and 0/imm32/false
|
|
74/jump-if-= break/disp8
|
|
(new-literal-integer Heap %esi *(ebp+0x10))
|
|
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
|
|
(new-literal Heap %esi *(ebp+0x10))
|
|
eb/jump $lookup-var-or-literal:end/disp8
|
|
}
|
|
# otherwise return lookup-var(name, vars)
|
|
{
|
|
(lookup-var %esi *(ebp+0xc)) # => eax
|
|
}
|
|
$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 Stderr "empty variable!")
|
|
(flush Stderr)
|
|
# . syscall(exit, 1)
|
|
bb/copy-to-ebx 1/imm32
|
|
b8/copy-to-eax 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# 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 (handle var)), out: (addr handle var)
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
# . save registers
|
|
50/push-eax
|
|
#
|
|
(lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x10))
|
|
# 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 Stderr "unknown variable '")
|
|
(write-slice-buffered Stderr *(ebp+8))
|
|
(write-buffered Stderr "'\n")
|
|
(flush Stderr)
|
|
# . syscall(exit, 1)
|
|
bb/copy-to-ebx 1/imm32
|
|
b8/copy-to-eax 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# never gets here
|
|
|
|
# return first 'name' from the top (back) of 'vars', and 0/null if not found
|
|
lookup-var-helper: # name: (addr slice), vars: (addr stack (handle var)), out: (addr handle var)
|
|
# pseudocode:
|
|
# var curr: (addr handle var) = &vars->data[vars->top - 8]
|
|
# var min = vars->data
|
|
# while curr >= min
|
|
# var v: (handle var) = *curr
|
|
# if v->name == name
|
|
# return
|
|
# curr -= 8
|
|
#
|
|
# . 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
|
|
# 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 - 8]
|
|
8d/copy-address *(esi+ebx) 3/r32/ebx
|
|
{
|
|
# 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
|
|
# 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
|
|
}
|
|
# curr -= 8
|
|
81 5/subop/subtract %ebx 8/imm32
|
|
e9/jump loop/disp32
|
|
}
|
|
$lookup-var-helper: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
|
|
|
|
$lookup-var-helper:error1:
|
|
(write-buffered Stderr "malformed stack when looking up '")
|
|
(write-slice-buffered Stderr *(ebp+8))
|
|
(write-buffered Stderr "'\n")
|
|
(flush Stderr)
|
|
# . syscall(exit, 1)
|
|
bb/copy-to-ebx 1/imm32
|
|
b8/copy-to-eax 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# never gets here
|
|
|
|
# return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found
|
|
lookup-or-define-var: # name: (addr slice), vars: (addr stack (handle var)), fn: (addr function), out: (addr handle var)
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
# . save registers
|
|
50/push-eax
|
|
#
|
|
(lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x14))
|
|
{
|
|
# 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))
|
|
81 7/subop/compare *eax 0/imm32
|
|
# otherwise abort
|
|
0f 84/jump-if-= $lookup-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
|
|
|
|
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)) # => 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
|
|
89/<- *(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
|
|
|
|
test-parse-mu-stmt:
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
# setup
|
|
(clear-stream _test-input-stream)
|
|
(write _test-input-stream "increment n\n")
|
|
# var vars/ecx: (stack (addr var) 16)
|
|
81 5/subop/subtract %esp 0x80/imm32
|
|
68/push 0x80/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))
|
|
# 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)
|
|
# 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
|
|
(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 0x80/imm32
|
|
68/push 0x80/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))
|
|
# 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)
|
|
# 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
|
|
$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)
|
|
# . 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
|
|
# 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->type = new tree()
|
|
8d/copy-address *(ecx+8) 0/r32/eax # Var-type
|
|
(allocate *(ebp+8) *Tree-size %eax)
|
|
(lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax
|
|
c7 0/subop/copy *eax 1/imm32/true # 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 Stderr "variable cannot begin with a digit '")
|
|
(write-slice-buffered Stderr *(ebp+0xc))
|
|
(write-buffered Stderr "'\n")
|
|
(flush Stderr)
|
|
# . syscall(exit, 1)
|
|
bb/copy-to-ebx 1/imm32
|
|
b8/copy-to-eax 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# never gets here
|
|
|
|
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 0/r32/eax
|
|
# s = slice-to-string(name)
|
|
(slice-to-string Heap *(ebp+0xc) %ecx)
|
|
# allocate to out
|
|
(new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
|
|
# ecx = out
|
|
8b/-> *(ebp+0x10) 1/r32/ecx
|
|
# out->type = new type
|
|
8d/copy-address *(ecx+8) 0/r32/eax # Var-type
|
|
(allocate *(ebp+8) *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 # 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)
|
|
(find-or-create-typeinfo-output-var %eax *(ebp+0xc) *(ebp+0x10))
|
|
$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
|
|
8b/-> *eax 0/r32/eax # Stmt-var-value
|
|
8b/-> *(eax+4) 0/r32/eax # Var-type
|
|
{
|
|
81 7/subop/compare *(eax+8) 0/imm32 # Tree-right
|
|
74/jump-if-= break/disp8
|
|
8b/-> *(eax+8) 0/r32/eax # Tree-right
|
|
8b/-> *(eax+4) 0/r32/eax # Tree-left
|
|
}
|
|
8b/-> *(eax+4) 0/r32/eax # Tree-value
|
|
$container-type: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
|
|
# 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:
|
|
# . 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
|
|
{
|
|
# if (*out == 0) break
|
|
81 7/subop/compare *edi 0/imm32
|
|
74/jump-if-= break/disp8
|
|
# 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
|
|
# *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 tmp-addr/edi: (addr typeinfo-entry) = find-or-create-typeinfo-fields(T, f)
|
|
# . var tmp/edi: (handle typeinfo-entry)
|
|
68/push 0/imm32
|
|
68/push 0/imm32
|
|
89/<- %edi 4/r32/esp
|
|
# . find-or-create-typeinfo-fields(T, f, tmp)
|
|
(find-or-create-typeinfo-fields *(ebp+8) *(ebp+0xc) %edi)
|
|
# . tmp-addr = lookup(tmp)
|
|
(lookup *edi *(edi+4)) # => eax
|
|
89/<- %edi 0/r32/eax
|
|
# if output var doesn't exist, create it
|
|
{
|
|
81 7/subop/compare *(edi+8) 0/imm32 # Typeinfo-entry-output-var
|
|
0f 85/jump-if-!= break/disp32
|
|
# out/edx = 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
|
|
(copy-array Heap "field" %eax)
|
|
# . new var
|
|
(new-var Heap *eax *(eax+4) *(ebp+0x10))
|
|
# . reclaim name
|
|
81 0/subop/add %esp 8/imm32
|
|
# save out in typeinfo
|
|
8b/-> *(ebp+0x10) 2/r32/edx
|
|
8b/-> *edx 0/r32/eax
|
|
89/<- *(edi+0xc) 0/r32/eax # Typeinfo-entry-output-var
|
|
8b/-> *(edx+4) 0/r32/eax
|
|
89/<- *(edi+0x10) 0/r32/eax # Typeinfo-entry-output-var
|
|
# initialize out
|
|
# . var out-addr/edx: (addr var) = lookup(*out)
|
|
(lookup *edx *(edx+4)) # => eax
|
|
89/<- %edx 0/r32/eax
|
|
# . out->type = new constant type
|
|
8d/copy-address *(edx+8) 0/r32/eax # Var-type
|
|
(allocate Heap *Tree-size %eax)
|
|
(lookup *(edx+8) *(edx+0xc)) # => eax
|
|
c7 0/subop/copy *eax 1/imm32/true # Tree-is-atom
|
|
c7 0/subop/copy *(eax+4) 6/imm32/constant # Tree-value
|
|
c7 0/subop/copy *(eax+8) 0/imm32 # Tree-left
|
|
c7 0/subop/copy *(eax+0xc) 0/imm32 # Tree-right
|
|
c7 0/subop/copy *(eax+0x10) 0/imm32 # Tree-right
|
|
# . out-addr->offset isn't filled out yet
|
|
c7 0/subop/copy *(edx+0x14) -1/imm32/uninitialized # Var-offset
|
|
}
|
|
$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
|
|
# esi = T->fields
|
|
8b/-> *(ebp+8) 6/r32/esi
|
|
8b/-> *(esi+4) 6/r32/esi # Typeinfo-fields
|
|
# var src/esi: (addr handle typeinfo-entry) = get-or-insert-slice(T->fields, f)
|
|
(get-or-insert-slice %esi *(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 *(ebp+0x10))
|
|
eb/jump $find-or-create-typeinfo-fields:end/disp8
|
|
}
|
|
# otherwise copy it
|
|
# . edi = out
|
|
8b/-> *(ebp+0x10) 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
|
|
$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)
|
|
# 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
|
|
{
|
|
$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:abort/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:
|
|
# var v/esi: (handle var) = parse-var-with-type(word-slice, first-line)
|
|
(parse-var-with-type %edx %ecx) # => eax
|
|
89/<- %esi 0/r32/eax
|
|
$populate-mu-type:create-typeinfo-fields:
|
|
# var r/ebx: (handle typeinfo-entry)
|
|
(find-or-create-typeinfo-fields %edi %edx) # => eax
|
|
89/<- %ebx 0/r32/eax
|
|
#? (write-buffered Stderr "var ")
|
|
#? (write-buffered Stderr *esi) # Var-name
|
|
#? (write-buffered Stderr " is at index ")
|
|
#? (print-int32-buffered Stderr *(ebp-4))
|
|
#? (write-buffered Stderr Newline)
|
|
#? (flush Stderr)
|
|
# r->index = curr-index
|
|
8b/-> *(ebp-4) 0/r32/eax
|
|
89/<- *(ebx+4) 0/r32/eax # Typeinfo-entry-index
|
|
# ++curr-index
|
|
ff 0/subop/increment *(ebp-4)
|
|
$populate-mu-type:set-input-type:
|
|
# r->input-var = v
|
|
89/<- *ebx 6/r32/esi # Typeinfo-entry-input-var
|
|
{
|
|
$populate-mu-type:create-output-type:
|
|
# if (r->output-var == 0) create a new var with some placeholder data
|
|
81 7/subop/compare *(ebx+8) 0/imm32 # Typeinfo-entry-output-var
|
|
75/jump-if-!= break/disp8
|
|
(new-literal Heap %edx) # => eax
|
|
89/<- *(ebx+8) 0/r32/eax # Typeinfo-entry-output-var
|
|
}
|
|
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+8) -2/imm32/uninitialized # Typeinfo-total-size-in-bytes
|
|
$populate-mu-type:end:
|
|
# . reclaim locals
|
|
81 0/subop/add %esp 0x214/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:abort:
|
|
# error("unexpected top-level command: " word-slice "\n")
|
|
(write-buffered Stderr "incomplete type definition '")
|
|
(type-name *edi) # Typeinfo-id => eax
|
|
(write-buffered Stderr %eax)
|
|
(write-buffered Stderr "\n")
|
|
(flush Stderr)
|
|
# . syscall(exit, 1)
|
|
bb/copy-to-ebx 1/imm32
|
|
b8/copy-to-eax 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# 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+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:
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
# . save registers
|
|
51/push-ecx
|
|
$populate-mu-type-sizes:total-sizes:
|
|
# var curr/ecx: (handle typeinfo) = *Program->types
|
|
8b/-> *_Program-types 1/r32/ecx
|
|
{
|
|
# if (curr == null) break
|
|
81 7/subop/compare %ecx 0/imm32
|
|
74/jump-if-= break/disp8
|
|
(populate-mu-type-sizes-in-type %ecx)
|
|
# curr = curr->next
|
|
8b/-> *(ecx+0xc) 1/r32/ecx # Typeinfo-next
|
|
eb/jump loop/disp8
|
|
}
|
|
$populate-mu-type-sizes:offsets:
|
|
# var curr/ecx: (handle typeinfo) = *Program->types
|
|
8b/-> *_Program-types 1/r32/ecx
|
|
{
|
|
# if (curr == null) break
|
|
81 7/subop/compare %ecx 0/imm32
|
|
74/jump-if-= break/disp8
|
|
(populate-mu-type-offsets %ecx)
|
|
# curr = curr->next
|
|
8b/-> *(ecx+0xc) 1/r32/ecx # Typeinfo-next
|
|
eb/jump loop/disp8
|
|
}
|
|
$populate-mu-type-sizes:end:
|
|
# . restore registers
|
|
59/pop-to-ecx
|
|
# . 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)
|
|
# . 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+8) 0/imm32 # Typeinfo-total-size-in-bytes
|
|
7d/jump-if->= $populate-mu-type-sizes-in-type:end/disp8
|
|
# if T is being computed, abort
|
|
81 7/subop/compare *(esi+8) -1/imm32/being-computed # Typeinfo-total-size-in-bytes
|
|
74/jump-if-= $populate-mu-type-sizes-in-type:abort/disp8
|
|
# tag T (-2 to -1) to avoid infinite recursion
|
|
c7 0/subop/copy *(esi+8) -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: (handle table string_key (handle typeinfo-entry)) = T->fields
|
|
8b/-> *(esi+4) 1/r32/ecx # Typeinfo-fields
|
|
# 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: (handle typeinfo-entry) = curr->value
|
|
8b/-> *(ecx+4) 0/r32/eax
|
|
# compute size of t
|
|
(compute-size-of-var *eax) # Typeinfo-entry-input-var => eax
|
|
# result += eax
|
|
01/add-to %edi 0/r32/eax
|
|
# curr += row-size
|
|
81 0/subop/add %ecx 8/imm32
|
|
#
|
|
eb/jump loop/disp8
|
|
}
|
|
# - save result
|
|
89/<- *(esi+8) 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 Stderr "cycle in type definitions\n")
|
|
(flush Stderr)
|
|
# . syscall(exit, 1)
|
|
bb/copy-to-ebx 1/imm32
|
|
b8/copy-to-eax 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# 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) -> result/eax: int
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
# . push registers
|
|
51/push-ecx
|
|
# var t/ecx: (addr tree type-id) = lookup(v->type)
|
|
8b/-> *(ebp+8) 1/r32/ecx
|
|
(lookup *(ecx+8) *(ecx+0xc)) # => eax
|
|
89/<- %ecx 0/r32/eax
|
|
# if (t->left-is-atom == false) t = lookup(t->left)
|
|
{
|
|
81 7/subop/compare *ecx 0/imm32/false # Tree-is-atom
|
|
75/jump-if-!= break/disp8
|
|
(lookup *(ecx+4) *(ecx+8)) # Tree-left Tree-left => eax
|
|
89/<- %ecx 0/r32/eax
|
|
}
|
|
# TODO: ensure t is an atom
|
|
(compute-size-of-type-id *(ecx+4)) # 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 -> result/eax: int
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
#
|
|
8b/-> *(ebp+8) 0/r32/eax
|
|
# if v is a literal, return 0
|
|
3d/compare-eax-and 0/imm32
|
|
74/jump-if-= $compute-size-of-type-id:end/disp8 # eax changes type from type-id to int
|
|
# if v has a user-defined type, compute its size
|
|
# TODO: support non-atom type
|
|
(find-typeinfo %eax) # => eax
|
|
{
|
|
3d/compare-eax-and 0/imm32
|
|
74/jump-if-= break/disp8
|
|
$compute-size-of-type-id:user-defined:
|
|
(populate-mu-type-sizes %eax)
|
|
8b/-> *(eax+8) 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:
|
|
# . 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)
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
# . save registers
|
|
50/push-eax
|
|
51/push-ecx
|
|
52/push-edx
|
|
53/push-ebx
|
|
56/push-esi
|
|
57/push-edi
|
|
# var curr-offset/edi: int = 0
|
|
bf/copy-to-edi 0/imm32
|
|
# var table/ecx: (addr table string_key (handle typeinfo-entry)) = lookup(T->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
|
|
7d/jump-if->= break/disp8
|
|
# var v/esi: (addr typeinfo-entry)
|
|
(locate-typeinfo-entry-with-index %ecx %ebx) # => eax
|
|
89/<- %esi 0/r32/eax
|
|
# 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)
|
|
# . eax: (addr 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
|
|
eb/jump loop/disp8
|
|
}
|
|
$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 -> 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>= $locate-typeinfo-entry-with-index:abort/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
|
|
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:
|
|
# . 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
|
|
|
|
$locate-typeinfo-entry-with-index:abort:
|
|
(write-buffered Stderr "overflowing typeinfo-entry->index ")
|
|
(print-int32-buffered Stderr %ecx)
|
|
(write-buffered Stderr "\n")
|
|
(flush Stderr)
|
|
# . syscall(exit, 1)
|
|
bb/copy-to-ebx 1/imm32
|
|
b8/copy-to-eax 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# never gets here
|
|
|
|
#######################################################
|
|
# Type-checking
|
|
#######################################################
|
|
|
|
check-mu-types:
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
#
|
|
$check-mu-types:end:
|
|
# . 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 tree type-id) = 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 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 (!t->is-atom?) t = lookup(t->left)
|
|
{
|
|
81 7/subop/compare *ecx 0/imm32/false # Tree-is-atom
|
|
75/jump-if-!= break/disp8
|
|
(lookup *(ecx+4) *(ecx+8)) # Tree-left Tree-left => eax
|
|
89/<- %ecx 0/r32/eax
|
|
}
|
|
# TODO: assert t->is-atom?
|
|
(size-of-type-id *(ecx+4)) # 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 tree type-id) = 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)) # Tree-right 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:end/disp8
|
|
}
|
|
# if (!t->is-atom?) t = lookup(t->left)
|
|
{
|
|
81 7/subop/compare *ecx 0/imm32/false # Tree-is-atom
|
|
75/jump-if-!= break/disp8
|
|
(lookup *(ecx+4) *(ecx+8)) # Tree-left Tree-left => eax
|
|
89/<- %ecx 0/r32/eax
|
|
}
|
|
# TODO: assert t->is-atom?
|
|
(size-of-type-id *(ecx+4)) # 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 tree type-id) -> 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
|
|
# result = false
|
|
b8/copy-to-eax 0/imm32/false
|
|
# if t->left-is-atom, return false
|
|
81 7/subop/compare *ecx 0/imm32/false # Tree-is-atom
|
|
75/jump-if-!= $is-mu-array?:end/disp8
|
|
# if !t->left->left-is-atom, return false
|
|
8b/-> *(ecx+4) 1/r32/ecx # Tree-left
|
|
81 7/subop/compare *ecx 0/imm32/false # Tree-is-atom
|
|
74/jump-if-= $is-mu-array?:end/disp8
|
|
# return t->left->value == array
|
|
81 7/subop/compare *(ecx+4) 3/imm32/array-type-id # Tree-value
|
|
0f 94/set-if-= %al
|
|
$is-mu-array?:end:
|
|
# . restore registers
|
|
59/pop-to-ecx
|
|
# . epilogue
|
|
89/<- %esp 5/r32/ebp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
size-of-array: # a: (addr tree type-id) -> 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'
|
|
8b/-> *(ecx+8) 1/r32/ecx # Tree-right
|
|
# var elem-type/edx: type-id = a->right->value
|
|
8b/-> *(ecx+4) 2/r32/edx # Tree-value
|
|
8b/-> *(edx+4) 2/r32/edx # Tree-value
|
|
# var array-size/ecx: int = a->right->right->left->value
|
|
8b/-> *(ecx+8) 1/r32/ecx # Tree-right
|
|
8b/-> *(ecx+4) 1/r32/ecx # Tree-left
|
|
8b/-> *(ecx+4) 1/r32/ecx # Tree-value
|
|
# return array-size * size-of(elem-type)
|
|
(size-of-type-id %edx) # => eax
|
|
f7 4/subop/multiply-into-eax %ecx
|
|
05/add-to-eax 4/imm32 # for array size
|
|
$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
|
|
|
|
size-of-type-id: # t: type-id -> result/eax: int
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
#
|
|
8b/-> *(ebp+8) 0/r32/eax
|
|
# if v is a literal, return 0
|
|
3d/compare-eax-and 0/imm32
|
|
74/jump-if-= $size-of-type-id:end/disp8 # eax changes type from type-id to int
|
|
# if v has a user-defined type, return its size
|
|
# TODO: support non-atom type
|
|
(find-typeinfo %eax) # => eax
|
|
{
|
|
3d/compare-eax-and 0/imm32
|
|
74/jump-if-= break/disp8
|
|
$size-of-type-id:user-defined:
|
|
8b/-> *(eax+8) 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:
|
|
# . epilogue
|
|
89/<- %esp 5/r32/ebp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
type-equal?: # a: (addr tree type-id), b: (addr tree type-id) -> result/eax: boolean
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
# . save registers
|
|
51/push-ecx
|
|
52/push-edx
|
|
# ecx = a
|
|
8b/-> *(ebp+8) 1/r32/ecx
|
|
# edx = b
|
|
8b/-> *(ebp+0xc) 2/r32/edx
|
|
# 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
|
|
74/jump-if-= $type-equal?:end/disp8
|
|
# if (a < MAX_TYPE_ID) return false
|
|
81 7/subop/compare %ecx 0x10000/imm32
|
|
b8/copy-to-eax 0/imm32/false
|
|
72/jump-if-addr< $type-equal?:end/disp8
|
|
# if (b < MAX_TYPE_ID) return false
|
|
81 7/subop/compare %edx 0x10000/imm32
|
|
b8/copy-to-eax 0/imm32/false
|
|
72/jump-if-addr< $type-equal?:end/disp8
|
|
# if (!type-equal?(a->left, b->left)) return false
|
|
(type-equal? *(ecx+4) *(edx+4)) # Tree-left, Tree-left => eax
|
|
3d/compare-eax-and 0/imm32/false
|
|
74/jump-if-= $type-equal?:end/disp8
|
|
# return type-equal?(a->right, b->right)
|
|
(type-equal? *(ecx+8) *(edx+8)) # Tree-right, Tree-right => eax
|
|
$type-equal?:end:
|
|
# . restore registers
|
|
5a/pop-to-edx
|
|
59/pop-to-ecx
|
|
# . epilogue
|
|
89/<- %esp 5/r32/ebp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
#######################################################
|
|
# Code-generation
|
|
#######################################################
|
|
|
|
== data
|
|
|
|
Curr-block-depth: # (addr int)
|
|
0/imm32
|
|
Curr-local-stack-offset: # (addr int)
|
|
0/imm32
|
|
|
|
== code
|
|
|
|
emit-subx: # out: (addr buffered-file)
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
# . save registers
|
|
50/push-eax
|
|
51/push-ecx
|
|
57/push-edi
|
|
# edi = out
|
|
8b/-> *(ebp+8) 7/r32/edi
|
|
# var curr/ecx: (addr function) = *Program->functions
|
|
(lookup *_Program-functions *_Program-functions->payload) # => eax
|
|
89/<- %ecx 0/r32/eax
|
|
{
|
|
# if (curr == null) break
|
|
81 7/subop/compare %ecx 0/imm32
|
|
0f 84/jump-if-= break/disp32
|
|
(emit-subx-function %edi %ecx)
|
|
# curr = curr->next
|
|
8b/-> *(ecx+0x14) 1/r32/ecx # Function-next
|
|
e9/jump loop/disp32
|
|
}
|
|
$emit-subx: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
|
|
|
|
emit-subx-function: # out: (addr buffered-file), f: (addr function)
|
|
# . 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
|
|
57/push-edi
|
|
# edi = out
|
|
8b/-> *(ebp+8) 7/r32/edi
|
|
# ecx = f
|
|
8b/-> *(ebp+0xc) 1/r32/ecx
|
|
# var vars/edx: (stack (addr var) 256)
|
|
81 5/subop/subtract %esp 0x800/imm32
|
|
68/push 0x800/imm32/size
|
|
68/push 0/imm32/top
|
|
89/<- %edx 4/r32/esp
|
|
#
|
|
(write-buffered %edi *ecx)
|
|
(write-buffered %edi ":\n")
|
|
# initialize some global state
|
|
c7 0/subop/copy *Curr-block-depth 1/imm32
|
|
c7 0/subop/copy *Curr-local-stack-offset 0/imm32
|
|
#
|
|
(emit-subx-prologue %edi)
|
|
(emit-subx-block %edi *(ecx+0x10) %edx) # Function-body
|
|
(emit-subx-epilogue %edi)
|
|
# 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 408/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
|
|
|
|
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: (handle list var) = f->inouts
|
|
8b/-> *(ebp+8) 1/r32/ecx
|
|
8b/-> *(ecx+8) 1/r32/ecx # Function-inouts
|
|
{
|
|
$populate-mu-type-offsets-in-inouts:loop:
|
|
81 7/subop/compare %ecx 0/imm32
|
|
74/jump-if-= break/disp8
|
|
# var v/ebx: (handle var) = curr->value
|
|
8b/-> *ecx 3/r32/ebx # List-value
|
|
# v->offset = next-offset
|
|
89/<- *(ebx+0xc) 2/r32/edx # Var-offset
|
|
# next-offset += size-of(v)
|
|
(size-of %ebx) # => eax
|
|
01/add-to %edx 0/r32/eax
|
|
# curr = curr->next
|
|
8b/-> *(ecx+4) 1/r32/ecx # List-next
|
|
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 (handle var))
|
|
# . 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 = stmts
|
|
8b/-> *(ebp+0xc) 6/r32/esi
|
|
# var var-seen?/edx: boolean <- copy false
|
|
ba/copy-to-edx 0/imm32/false
|
|
#
|
|
{
|
|
$emit-subx-stmt-list:loop:
|
|
81 7/subop/compare %esi 0/imm32
|
|
0f 84/jump-if-= break/disp32
|
|
# var curr-stmt/ecx = stmts->value
|
|
8b/-> *esi 1/r32/ecx # List-value
|
|
{
|
|
$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))
|
|
}
|
|
{
|
|
$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:
|
|
# if !var-seen? break
|
|
81 7/subop/compare %edx 0/imm32/false
|
|
0f 84/jump-if-= break/disp32
|
|
$emit-subx-stmt-list:branch-stmt-and-var-seen:
|
|
# unconditional loops {{{
|
|
{
|
|
# if (!string-equal?(var->operation, "loop")) break
|
|
(string-equal? *(ecx+4) "loop") # Stmt1-operation => 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+8) 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:cleanup/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:cleanup/disp32
|
|
}
|
|
}
|
|
# }}}
|
|
# unconditional breaks {{{
|
|
{
|
|
# if (!string-equal?(curr-stmt->operation, "break")) break
|
|
(string-equal? *(ecx+4) "break") # Stmt1-operation => 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+8) 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:cleanup/disp32
|
|
}
|
|
# }}}
|
|
# simple conditional branches without a target {{{
|
|
81 7/subop/compare *(ecx+8) 0/imm32 # Stmt1-inouts
|
|
{
|
|
0f 85/jump-if-!= break/disp32
|
|
$emit-subx-stmt-list:zero-arg-conditional-branch:
|
|
# var old-block-depth/eax: 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
|
|
(string-starts-with? *(ecx+4) "break")
|
|
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)
|
|
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
|
|
# var-seen? = true
|
|
ba/copy-to-edx 1/imm32/true
|
|
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))
|
|
# emit the instruction as usual
|
|
(emit-subx-stmt *(ebp+8) %ecx Primitives)
|
|
# var-seen? = true
|
|
ba/copy-to-edx 1/imm32/true
|
|
eb/jump $emit-subx-stmt-list:continue/disp8
|
|
}
|
|
$emit-subx-stmt-list:continue:
|
|
# TODO: raise an error on unrecognized Stmt-tag
|
|
8b/-> *(esi+4) 6/r32/esi # List-next
|
|
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:cleanup:
|
|
(clean-up-blocks *(ebp+0x10) *Curr-block-depth)
|
|
$emit-subx-stmt-list: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
|
|
|
|
push-output-and-maybe-emit-spill: # out: (addr buffered-file), stmt: (addr reg-var-def), vars: (addr stack (handle var))
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
# . save registers
|
|
51/push-ecx
|
|
# 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
|
|
# push(vars, sv->value)
|
|
(push *(ebp+0x10) *eax) # Stmt-var-value
|
|
(push *(ebp+0x10) *(eax+4)) # Stmt-var-value
|
|
# 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
|
|
# 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
|
|
# if already-spilled-this-block?(reg, vars) return
|
|
(already-spilled-this-block? %ecx *(ebp+0x10)) # => eax
|
|
3d/compare-eax-and 0/imm32/false
|
|
75/jump-if-!= $push-output-and-maybe-emit-spill:end/disp8
|
|
# TODO: assert(size-of(output) == 4)
|
|
# *Curr-local-stack-offset -= 4
|
|
81 5/subop/subtract *Curr-local-stack-offset 4/imm32
|
|
# emit spill
|
|
(emit-indent *(ebp+8) *Curr-block-depth)
|
|
(write-buffered *(ebp+8) "ff 6/subop/push %")
|
|
(lookup *(ecx+0x18) *(ecx+0x1c)) # Var-register Var-register => eax
|
|
(write-buffered *(ebp+8) %eax)
|
|
(write-buffered *(ebp+8) Newline)
|
|
$push-output-and-maybe-emit-spill:end:
|
|
# . restore registers
|
|
59/pop-to-ecx
|
|
# . 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 Stderr "var '")
|
|
(write-buffered Stderr *eax) # Var-name
|
|
(write-buffered Stderr "' initialized from an instruction must live in a register\n")
|
|
(flush Stderr)
|
|
# . syscall(exit, 1)
|
|
bb/copy-to-ebx 1/imm32
|
|
b8/copy-to-eax 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# never gets here
|
|
|
|
emit-subx-cleanup-and-unconditional-nonlocal-branch: # out: (addr buffered-file), stmt: (addr stmt1), vars: (addr stack (handle var))
|
|
# . 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 target/edx: (addr array byte) = curr-stmt->inouts->value->name
|
|
8b/-> *(ecx+8) 2/r32/edx # Stmt1-inouts
|
|
8b/-> *edx 2/r32/edx # Stmt-var-value
|
|
8b/-> *edx 2/r32/edx # Var-name
|
|
# clean up until target block
|
|
(emit-cleanup-code-until-target *(ebp+8) *(ebp+0x10) %edx)
|
|
# emit jump to target block
|
|
(emit-indent *(ebp+8) *Curr-block-depth)
|
|
(write-buffered *(ebp+8) "e9/jump ")
|
|
(write-buffered *(ebp+8) %edx)
|
|
(string-starts-with? *(ecx+4) "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
|
|
5a/pop-to-edx
|
|
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 = stmt
|
|
8b/-> *(ebp+8) 1/r32/ecx
|
|
# if (stmt->operation starts with "loop") return true
|
|
(string-starts-with? *(ecx+4) "loop") # Stmt1-operation => 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+4) "break") # Stmt1-operation => 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
|
|
#
|
|
(get Reverse-branch *(eax+4) 8 "reverse-branch: ") # Stmt1-operation => eax: (addr addr array byte)
|
|
(emit-indent *(ebp+8) *Curr-block-depth)
|
|
(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
|
|
|
|
Reverse-branch: # (table string string)
|
|
# a table is a stream
|
|
0xa0/imm32/write
|
|
0/imm32/read
|
|
0xa0/imm32/size
|
|
# data
|
|
"break-if-="/imm32 "0f 85/jump-if-!="/imm32
|
|
"loop-if-="/imm32 "0f 85/jump-if-!="/imm32
|
|
"break-if-!="/imm32 "0f 84/jump-if-="/imm32
|
|
"loop-if-!="/imm32 "0f 84/jump-if-="/imm32
|
|
"break-if-<"/imm32 "0f 8d/jump-if->="/imm32
|
|
"loop-if-<"/imm32 "0f 8d/jump-if->="/imm32
|
|
"break-if->"/imm32 "0f 8e/jump-if-<="/imm32
|
|
"loop-if->"/imm32 "0f 8e/jump-if-<="/imm32
|
|
"break-if-<="/imm32 "0f 87/jump-if->"/imm32
|
|
"loop-if-<="/imm32 "0f 87/jump-if->"/imm32
|
|
"break-if->="/imm32 "0f 8c/jump-if-<"/imm32
|
|
"loop-if->="/imm32 "0f 8c/jump-if-<"/imm32
|
|
"break-if-addr<"/imm32 "0f 83/jump-if-addr>="/imm32
|
|
"loop-if-addr<"/imm32 "0f 83/jump-if-addr>="/imm32
|
|
"break-if-addr>"/imm32 "0f 86/jump-if-addr<="/imm32
|
|
"loop-if-addr>"/imm32 "0f 86/jump-if-addr<="/imm32
|
|
"break-if-addr<="/imm32 "0f 87/jump-if-addr>"/imm32
|
|
"loop-if-addr<="/imm32 "0f 87/jump-if-addr>"/imm32
|
|
"break-if-addr>="/imm32 "0f 82/jump-if-addr<"/imm32
|
|
"loop-if-addr>="/imm32 "0f 82/jump-if-addr<"/imm32
|
|
|
|
== code
|
|
|
|
emit-unconditional-jump-to-depth: # out: (addr buffered-file), vars: (addr stack (handle 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
|
|
# ecx = vars
|
|
8b/-> *(ebp+0xc) 1/r32/ecx
|
|
# var eax: int = vars->top
|
|
8b/-> *ecx 0/r32/eax
|
|
# var min/ecx: (addr handle var) = vars->data
|
|
81 0/subop/add %ecx 8/imm32
|
|
# var curr/eax: (addr handle var) = &vars->data[vars->top - 4]
|
|
81 5/subop/subtract %eax 4/imm32
|
|
8d/copy-address *(ecx+eax) 0/r32/eax
|
|
# edx = depth
|
|
8b/-> *(ebp+0x10) 2/r32/edx
|
|
{
|
|
$emit-unconditional-jump-to-depth:loop:
|
|
# if (curr < min) break
|
|
39/compare %eax 1/r32/ecx
|
|
0f 82/jump-if-addr< break/disp32
|
|
# var v/ebx: (handle var) = *curr
|
|
8b/-> *eax 3/r32/ebx
|
|
# if (v->block-depth < until-block-depth) break
|
|
39/compare *(ebx+8) 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+8) 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
|
|
# . var eax: int = size-of(v)
|
|
50/push-eax
|
|
(size-of %ebx) # => eax
|
|
# . if (eax != 0) continue
|
|
3d/compare-eax-and 0/imm32
|
|
58/pop-to-eax
|
|
#
|
|
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 ")
|
|
(write-buffered *(ebp+8) *ebx) # Var-name
|
|
(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 -= 4
|
|
2d/subtract-from-eax 4/imm32
|
|
e9/jump loop/disp32
|
|
}
|
|
# TODO: error if no label at 'depth' was found
|
|
$emit-unconditional-jump-to-depth: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
|
|
|
|
# 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 (handle 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
|
|
# ecx = vars
|
|
8b/-> *(ebp+0xc) 1/r32/ecx
|
|
# var eax: int = vars->top
|
|
8b/-> *ecx 0/r32/eax
|
|
# var min/ecx: (addr handle var) = vars->data
|
|
81 0/subop/add %ecx 8/imm32
|
|
# var curr/eax: (addr handle var) = &vars->data[vars->top - 4]
|
|
81 5/subop/subtract %eax 4/imm32
|
|
8d/copy-address *(ecx+eax) 0/r32/eax
|
|
# edx = until-block-depth
|
|
8b/-> *(ebp+0x10) 2/r32/edx
|
|
{
|
|
$emit-cleanup-code-until-depth:loop:
|
|
# if (curr < min) break
|
|
39/compare %eax 1/r32/ecx
|
|
0f 82/jump-if-addr< break/disp32
|
|
# var v/ebx: (handle var) = *curr
|
|
8b/-> *eax 3/r32/ebx
|
|
# if (v->block-depth < until-block-depth) break
|
|
39/compare *(ebx+8) 2/r32/edx # Var-block-depth
|
|
0f 8c/jump-if-< break/disp32
|
|
# if v is in a register
|
|
81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register
|
|
{
|
|
0f 84/jump-if-= break/disp32
|
|
50/push-eax
|
|
{
|
|
$emit-cleanup-code-until-depth:check-for-previous-spill:
|
|
(same-register-spilled-before? %ebx *(ebp+0xc) %eax) # => eax
|
|
3d/compare-eax-and 0/imm32/false
|
|
0f 85/jump-if-!= break/disp32
|
|
$emit-cleanup-code-until-depth:reclaim-var-in-register:
|
|
(emit-indent *(ebp+8) *Curr-block-depth)
|
|
(write-buffered *(ebp+8) "8f 0/subop/pop %")
|
|
(write-buffered *(ebp+8) *(ebx+0x10))
|
|
(write-buffered *(ebp+8) Newline)
|
|
}
|
|
58/pop-to-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:reclaim-var-on-stack:
|
|
50/push-eax
|
|
(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 ")
|
|
(print-int32-buffered *(ebp+8) %eax)
|
|
(write-buffered *(ebp+8) "/imm32\n")
|
|
58/pop-to-eax
|
|
}
|
|
$emit-cleanup-code-until-depth:continue:
|
|
# curr -= 4
|
|
2d/subtract-from-eax 4/imm32
|
|
e9/jump loop/disp32
|
|
}
|
|
$emit-cleanup-code-until-depth: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
|
|
|
|
# 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 (handle 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 min/ecx: (addr handle var) = vars->data
|
|
81 0/subop/add %ecx 8/imm32
|
|
# var curr/edx: (addr handle var) = &vars->data[vars->top - 4]
|
|
81 5/subop/subtract %eax 4/imm32
|
|
8d/copy-address *(ecx+eax) 2/r32/edx
|
|
{
|
|
$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) = *curr
|
|
8b/-> *edx 3/r32/ebx
|
|
# if (v->name == until-block-label) break
|
|
(string-equal? *ebx *(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+0x10) 0/imm32 # Var-register
|
|
{
|
|
74/jump-if-= break/disp8
|
|
50/push-eax
|
|
{
|
|
$emit-cleanup-code-until-target:check-for-previous-spill:
|
|
(same-register-spilled-before? %ebx *(ebp+0xc) %edx) # => eax
|
|
3d/compare-eax-and 0/imm32/false
|
|
75/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 %")
|
|
(write-buffered *(ebp+8) *(ebx+0x10))
|
|
(write-buffered *(ebp+8) Newline)
|
|
}
|
|
58/pop-to-eax
|
|
eb/jump $emit-cleanup-code-until-target:continue/disp8
|
|
}
|
|
# otherwise v is on the stack
|
|
{
|
|
75/jump-if-!= break/disp8
|
|
$emit-cleanup-code-until-target:reclaim-var-on-stack:
|
|
(size-of %ebx) # => eax
|
|
# don't emit code for labels
|
|
3d/compare-eax-and 0/imm32
|
|
74/jump-if-= break/disp8
|
|
#
|
|
(emit-indent *(ebp+8) *Curr-block-depth)
|
|
(write-buffered *(ebp+8) "81 0/subop/add %esp ")
|
|
(print-int32-buffered *(ebp+8) %eax)
|
|
(write-buffered *(ebp+8) "/imm32\n")
|
|
}
|
|
$emit-cleanup-code-until-target:continue:
|
|
# curr -= 4
|
|
81 5/subop/subtract %edx 4/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
|
|
|
|
# is there already a var with the same block-depth and register as 'v' on the 'vars' stack?
|
|
# v is guaranteed not to be within vars
|
|
already-spilled-this-block?: # v: (addr var), vars: (addr stack (handle 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 min/ecx: (addr handle var) = vars->data
|
|
81 0/subop/add %ecx 8/imm32
|
|
# var curr/edx: (addr handle var) = &vars->data[vars->top - 4]
|
|
81 5/subop/subtract %eax 4/imm32
|
|
8d/copy-address *(ecx+eax) 2/r32/edx
|
|
# var depth/ebx: int = v->block-depth
|
|
8b/-> *(ebp+8) 3/r32/ebx
|
|
8b/-> *(ebx+8) 3/r32/ebx # Var-block-depth
|
|
# var needle/esi: (handle array byte) = v->register
|
|
8b/-> *(ebp+8) 6/r32/esi
|
|
8b/-> *(esi+0x10) 6/r32/esi # Var-register
|
|
{
|
|
$already-spilled-this-block?:loop:
|
|
# if (curr < min) break
|
|
39/compare %edx 1/r32/ecx
|
|
0f 82/jump-if-addr< break/disp32
|
|
# var cand/edi: (handle var) = *curr
|
|
8b/-> *edx 7/r32/edi
|
|
# if (cand->block-depth < depth) break
|
|
39/compare *(edi+8) 3/r32/ebx # Var-block-depth
|
|
0f 8c/jump-if-< break/disp32
|
|
# var cand-reg/edi: (handle array byte) = cand->reg
|
|
8b/-> *(edi+0x10) 7/r32/edi
|
|
# if (cand-reg == null) continue
|
|
{
|
|
$already-spilled-this-block?:check-reg:
|
|
81 7/subop/compare %edi 0/imm32
|
|
74/jump-if-= break/disp8
|
|
# if (cand-reg == needle) return true
|
|
(string-equal? %esi %edi) # => eax
|
|
3d/compare-eax-and 0/imm32/false
|
|
74/jump-if-= break/disp8
|
|
b8/copy-to-eax 1/imm32/true
|
|
eb/jump $already-spilled-this-block?:end/disp8
|
|
}
|
|
$already-spilled-this-block?:continue:
|
|
# curr -= 4
|
|
81 5/subop/subtract %edx 4/imm32
|
|
e9/jump loop/disp32
|
|
}
|
|
# return false
|
|
b8/copy-to-eax 0/imm32/false
|
|
$already-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
|
|
|
|
# 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 handle 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: (handle array byte) = v->register
|
|
8b/-> *(ecx+0x10) 2/r32/edx # Var-register
|
|
# var depth/ebx: int = v->block-depth
|
|
8b/-> *(ecx+8) 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 -= 4
|
|
81 5/subop/subtract %esi 4/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: (handle var) = *curr
|
|
8b/-> *esi 0/r32/eax
|
|
# if (x->block-depth < depth) break
|
|
39/compare *(eax+8) 3/r32/ebx # Var-block-depth
|
|
0f 8c/jump-if-< break/disp32
|
|
# if (x->register == 0) continue
|
|
81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register
|
|
74/jump-if-= $same-register-spilled-before?:continue/disp8
|
|
# if (x->register == reg) return true
|
|
(string-equal? *(eax+0x10) %edx) # Var-register => eax
|
|
3d/compare-eax-and 0/imm32/false
|
|
75/jump-if-!= $same-register-spilled-before?:end/disp8
|
|
$same-register-spilled-before?:continue:
|
|
# curr -= 4
|
|
81 5/subop/subtract %esi 4/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
|
|
clean-up-blocks: # vars: (addr stack (handle var)), until-block-depth: int
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
# . save registers
|
|
50/push-eax
|
|
51/push-ecx
|
|
56/push-esi
|
|
# esi = vars
|
|
8b/-> *(ebp+8) 6/r32/esi
|
|
# ecx = until-block-depth
|
|
8b/-> *(ebp+0xc) 1/r32/ecx
|
|
{
|
|
$clean-up-blocks:reclaim-loop:
|
|
# if (vars->top <= 0) break
|
|
81 7/subop/compare *esi 0/imm32 # Stack-top
|
|
7e/jump-if-<= break/disp8
|
|
# var v/eax: (handle var) = top(vars)
|
|
(top %esi) # => eax
|
|
# if (v->block-depth < until-block-depth) break
|
|
39/compare *(eax+8) 1/r32/ecx # Var-block-depth
|
|
7c/jump-if-< break/disp8
|
|
# if v is on the stack, update Curr-local-stack-offset
|
|
81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register
|
|
{
|
|
75/jump-if-!= break/disp8
|
|
$clean-up-blocks:reclaim-var-on-stack:
|
|
(size-of %eax) # => eax
|
|
01/add-to *Curr-local-stack-offset 0/r32/eax
|
|
}
|
|
(pop %esi)
|
|
e9/jump loop/disp32
|
|
}
|
|
$clean-up-blocks:end:
|
|
# . restore registers
|
|
5e/pop-to-esi
|
|
59/pop-to-ecx
|
|
58/pop-to-eax
|
|
# . epilogue
|
|
89/<- %esp 5/r32/ebp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
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: (handle var)
|
|
8b/-> *(eax+4) 1/r32/ecx # Vardef-var
|
|
# v->block-depth = *Curr-block-depth
|
|
8b/-> *Curr-block-depth 0/r32/eax
|
|
89/<- *(ecx+8) 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+0xc) 0/r32/eax # Var-offset
|
|
# if v is an array, do something special
|
|
{
|
|
(is-mu-array? *(ecx+4)) # Var-type => 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-indent *(ebp+8) *Curr-block-depth)
|
|
(write-buffered *(ebp+8) "(push-n-zero-bytes ")
|
|
(print-int32-buffered *(ebp+8) %edx)
|
|
(write-buffered *(ebp+8) ")\n")
|
|
(emit-indent *(ebp+8) *Curr-block-depth)
|
|
(write-buffered *(ebp+8) "68/push ")
|
|
(print-int32-buffered *(ebp+8) %edx)
|
|
(write-buffered *(ebp+8) "/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-subx-stmt: # out: (addr buffered-file), stmt: (addr stmt), primitives: (addr primitive)
|
|
# . 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))
|
|
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))
|
|
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))
|
|
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
|
|
}
|
|
# - 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
|
|
|
|
# TODO: actually return the length in array elements, rather than the size in bytes
|
|
translate-mu-length-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
|
|
# ecx = stmt
|
|
8b/-> *(ebp+0xc) 1/r32/ecx
|
|
#
|
|
(emit-indent *(ebp+8) *Curr-block-depth)
|
|
(write-buffered *(ebp+8) "8b/-> *")
|
|
# var base/eax: (handle var) = inouts[0]
|
|
8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts or Regvardef-inouts
|
|
8b/-> *eax 0/r32/eax # Stmt-var-value
|
|
# if base is an (addr array ...) in a register
|
|
{
|
|
81 7/subop/compare *(eax+0x10)) 0/imm32 # Var-register
|
|
74/jump-if-= break/disp8
|
|
(write-buffered *(ebp+8) *(eax+0x10)) # Var-register
|
|
eb/jump $translate-mu-length-stmt:emit-output/disp8
|
|
}
|
|
# otherwise if base is an (array ...) on the stack
|
|
{
|
|
81 7/subop/compare *(eax+0xc)) 0/imm32 # Var-offset
|
|
74/jump-if-= break/disp8
|
|
(write-buffered *(ebp+8) "(ebp+")
|
|
(print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-offset
|
|
(write-buffered *(ebp+8) ")")
|
|
}
|
|
$translate-mu-length-stmt:emit-output:
|
|
(write-buffered *(ebp+8) " ")
|
|
# outputs[0] "/r32"
|
|
8b/-> *(ecx+0xc) 0/r32/eax # Stmt1-outputs
|
|
8b/-> *eax 0/r32/eax # Stmt-var-value
|
|
(get Registers *(eax+0x10) 0xc "Registers") # Var-register => eax
|
|
(print-int32-buffered *(ebp+8) *eax)
|
|
(write-buffered *(ebp+8) "/r32\n")
|
|
$translate-mu-length-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-index-stmt: # out: (addr buffered-file), stmt: (addr stmt)
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
# . save registers
|
|
51/push-ecx
|
|
# var base/ecx: (handle var) = stmt->inouts[0]
|
|
8b/-> *(ebp+0xc) 1/r32/ecx
|
|
8b/-> *(ecx+8) 1/r32/ecx # Stmt1-inouts
|
|
8b/-> *ecx 1/r32/ecx # Stmt-var-value
|
|
# if (var->register) do one thing
|
|
{
|
|
81 7/subop/compare *(ecx+0x10) 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))
|
|
eb/jump $translate-mu-index-stmt:end/disp8
|
|
}
|
|
# if (var->offset) do a different thing
|
|
{
|
|
81 7/subop/compare *(ecx+0xc) 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))
|
|
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 Stderr "couldn't translate an index instruction. second (index) input must either lie in a register or be a literal\n")
|
|
(flush Stderr)
|
|
# . syscall(exit, 1)
|
|
bb/copy-to-ebx 1/imm32
|
|
b8/copy-to-eax 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# never gets here
|
|
|
|
$translate-mu-index-stmt-with-array:error2:
|
|
(write-buffered Stderr "couldn't translate an index instruction. second (index) input when in a register must be an int or offset\n")
|
|
(flush Stderr)
|
|
# . syscall(exit, 1)
|
|
bb/copy-to-ebx 1/imm32
|
|
b8/copy-to-eax 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# never gets here
|
|
|
|
translate-mu-index-stmt-with-array-in-register: # 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
|
|
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: (handle var) = inouts[0]
|
|
8b/-> *(ecx+8) 3/r32/ebx # Stmt1-inouts
|
|
8b/-> *ebx 3/r32/ebx # Stmt-var-value
|
|
# print base->register " + "
|
|
(write-buffered *(ebp+8) *(ebx+0x10)) # Var-register
|
|
#
|
|
(write-buffered *(ebp+8) " + ")
|
|
# var index/edx: (handle var) = inouts[1]
|
|
8b/-> *(ecx+8) 2/r32/edx # Stmt1-inouts
|
|
8b/-> *(edx+4) 2/r32/edx # Stmt-var-next
|
|
8b/-> *edx 2/r32/edx # Stmt-var-value
|
|
# if index->register
|
|
81 7/subop/compare *(edx+0x10) 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
|
|
(is-simple-mu-type? *(edx+4) 1) # Var-type, 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(size-of(element(base->type))) " + 4) "
|
|
# . index->register "<<"
|
|
(write-buffered *(ebp+8) *(edx+0x10)) # Var-register
|
|
(write-buffered *(ebp+8) "<<")
|
|
# . log2(size-of(element(base->type)))
|
|
# TODO: ensure size is a power of 2
|
|
(array-element-type-id %ebx) # => eax
|
|
(size-of-type-id %eax) # => eax
|
|
(num-shift-rights %eax) # => eax
|
|
(print-int32-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 # Tree-is-atom
|
|
0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
|
|
# if index has type (offset ...)
|
|
(is-simple-mu-type? *(eax+4) 7) # Tree-left, offset => eax
|
|
3d/compare-eax-and 0/imm32/false
|
|
{
|
|
0f 84/jump-if-= break/disp32
|
|
# print index->register " + 4) "
|
|
$translate-mu-index-stmt-with-array-in-register:emit-offset-register-index:
|
|
(write-buffered *(ebp+8) *(edx+0x10)) # Var-register
|
|
}
|
|
$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
|
|
(is-simple-mu-type? *(edx+4) 0) # Var-type => 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)
|
|
(parse-hex-int *edx) # Var-name => eax
|
|
89/<- %edx 0/r32/eax
|
|
# offset = idx-value * size-of(element(base->type))
|
|
(array-element-type-id %ebx) # => eax
|
|
(size-of-type-id %eax) # => eax
|
|
f7 4/subop/multiply-into-eax %edx # clobbers edx
|
|
# offset += 4 for array size
|
|
05/add-to-eax 4/imm32
|
|
# TODO: check edx for overflow
|
|
# print offset
|
|
(print-int32-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
|
|
8b/-> *(ecx+0xc) 0/r32/eax # Stmt1-outputs
|
|
8b/-> *eax 0/r32/eax # Stmt-var-value
|
|
(get Registers *(eax+0x10) 0xc "Registers") # Var-register => eax
|
|
(print-int32-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)
|
|
# . 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/eax = stmt->inouts
|
|
8b/-> *(ebp+0xc) 0/r32/eax
|
|
# var base/ecx: (handle var) = stmt->inouts[0]
|
|
8b/-> *(eax+8) 0/r32/eax # Stmt1-inouts
|
|
8b/-> *eax 1/r32/ecx # Stmt-var-value
|
|
# curr = curr->next
|
|
8b/-> *(eax+4) 0/r32/eax # Stmt-var-next
|
|
# var index/edx: (handle var) = stmt->inouts[1]
|
|
8b/-> *eax 2/r32/edx # Stmt-var-value
|
|
# if index->register
|
|
81 7/subop/compare *(edx+0x10) 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
|
|
(is-simple-mu-type? *(edx+4) 1) # Var-type, 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(size-of(element-type(base))) " + " base->offset+4
|
|
# . inouts[1]->register "<<"
|
|
(write-buffered *(ebp+8) *(edx+0x10)) # Var-register
|
|
(write-buffered *(ebp+8) "<<")
|
|
# . log2(size-of(element(base)))
|
|
# TODO: ensure size is a power of 2
|
|
(array-element-type-id %ecx) # => eax
|
|
(size-of-type-id %eax) # => eax
|
|
(num-shift-rights %eax) # => eax
|
|
(print-int32-buffered *(ebp+8) %eax)
|
|
#
|
|
(write-buffered *(ebp+8) " + ")
|
|
#
|
|
8b/-> *(ecx+0xc) 0/r32/eax # Var-offset
|
|
05/add-to-eax 4/imm32
|
|
(print-int32-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 # Tree-is-atom
|
|
0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
|
|
# if index has type (offset ...)
|
|
(is-simple-mu-type? *(eax+4) 7) # Tree-left, offset => 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:
|
|
(write-buffered *(ebp+8) *(edx+0x10)) # Var-register
|
|
}
|
|
$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
|
|
(is-simple-mu-type? *(edx+4) 0) # Var-type => 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)
|
|
(parse-hex-int *edx) # Var-name => eax
|
|
89/<- %ebx 0/r32/eax
|
|
# offset = idx-value * size-of(element-type(base->type))
|
|
(array-element-type-id %ecx) # => eax
|
|
(size-of-type-id %eax) # => eax
|
|
f7 4/subop/multiply-into-eax %ebx # clobbers edx
|
|
# offset += base->offset
|
|
03/add *(ecx+0xc) 0/r32/eax # Var-offset
|
|
# offset += 4 for array size
|
|
05/add-to-eax 4/imm32
|
|
# TODO: check edx for overflow
|
|
# print offset
|
|
(print-int32-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
|
|
8b/-> *(eax+0xc) 0/r32/eax # Stmt1-outputs
|
|
8b/-> *eax 0/r32/eax # Stmt-var-value
|
|
(get Registers *(eax+0x10) 0xc "Registers") # Var-register => eax
|
|
(print-int32-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)
|
|
# . 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/edx: (handle stmt-var) = stmt->inouts[0]
|
|
8b/-> *(ecx+8) 2/r32/edx # Stmt1-inouts
|
|
$translate-mu-compute-index-stmt:emit-index:
|
|
(emit-subx-var-as-rm32 *(ebp+8) *(edx+4)) # Stmt-var-next
|
|
(write-buffered *(ebp+8) Space)
|
|
$translate-mu-compute-index-stmt:emit-elem-size:
|
|
# var base/ebx: (handle var)
|
|
8b/-> *edx 3/r32/ebx # Stmt-var-value
|
|
# print size-of(element(base->type))
|
|
(array-element-type-id %ebx) # => eax
|
|
(size-of-type-id %eax) # => eax
|
|
(print-int32-buffered *(ebp+8) %eax)
|
|
(write-buffered *(ebp+8) "/imm32 ")
|
|
$translate-mu-compute-index-stmt:emit-output:
|
|
# outputs[0] "/r32"
|
|
8b/-> *(ecx+0xc) 0/r32/eax # Stmt1-outputs
|
|
8b/-> *eax 0/r32/eax # Stmt-var-value
|
|
(get Registers *(eax+0x10) 0xc "Registers") # Var-register => eax
|
|
(print-int32-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: (handle var) = stmt->inouts[0]
|
|
8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts
|
|
8b/-> *eax 0/r32/eax # Stmt-var-value
|
|
# if base is in a register
|
|
81 7/subop/compare *(eax+0x10) 0/imm32
|
|
{
|
|
0f 84/jump-if-= break/disp32
|
|
$translate-mu-get-stmt:emit-register-input:
|
|
# "*(" inouts[0]->register " + " offset ")"
|
|
(write-buffered *(ebp+8) "*(")
|
|
(write-buffered *(ebp+8) *(eax+0x10)) # Var-register
|
|
(write-buffered *(ebp+8) " + ")
|
|
(print-int32-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:
|
|
# "*(ebp + " inouts[0]->offset + offset ")"
|
|
(write-buffered *(ebp+8) "*(ebp+")
|
|
03/add *(eax+0xc) 2/r32/edx # Var-offset
|
|
(print-int32-buffered *(ebp+8) %edx)
|
|
(write-buffered *(ebp+8) ") ")
|
|
eb/jump $translate-mu-get-stmt:emit-output/disp8
|
|
}
|
|
$translate-mu-get-stmt:emit-output:
|
|
# outputs[0] "/r32"
|
|
8b/-> *(ecx+0xc) 0/r32/eax # Stmt1-outputs
|
|
8b/-> *eax 0/r32/eax # Stmt-var-value
|
|
(get Registers *(eax+0x10) 0xc "Registers") # Var-register => eax
|
|
(print-int32-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
|
|
|
|
array-element-type-id: # v: (addr var) -> result/eax: type-id
|
|
# precondition: n is positive
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
#
|
|
8b/-> *(ebp+8) 0/r32/eax
|
|
8b/-> *(eax+4) 0/r32/eax # Var-type
|
|
# TODO: ensure type->left is 'addr'
|
|
8b/-> *(eax+8) 0/r32/eax # Tree-right
|
|
# TODO: ensure that type->right is non-null
|
|
# TODO: ensure that type->right->left is 'array'
|
|
8b/-> *(eax+8) 0/r32/eax # Tree-right
|
|
# TODO: ensure that type->right->right is non-null
|
|
8b/-> *(eax+4) 0/r32/eax # Tree-left
|
|
8b/-> *(eax+4) 0/r32/eax # Tree-value
|
|
$array-element-type-id:end:
|
|
# . epilogue
|
|
89/<- %esp 5/r32/ebp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
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: (handle stmt-var) = stmt->inouts->next
|
|
8b/-> *(ebp+8) 0/r32/eax
|
|
8b/-> *(eax+8) 0/r32/eax # Stmt1-inouts
|
|
8b/-> *(eax+4) 0/r32/eax # Stmt-var-next
|
|
# var output-var/eax: (handle var) = second-inout->value
|
|
8b/-> *eax 0/r32/eax # Stmt-var-value
|
|
# return output-var->offset
|
|
8b/-> *(eax+0xc) 0/r32/eax # Var-offset
|
|
$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 (handle var))
|
|
# . 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
|
|
8b/-> *(esi+8) 0/r32/eax # Block-var
|
|
8b/-> *Curr-block-depth 1/r32/ecx
|
|
89/<- *(eax+8) 1/r32/ecx # Var-block-depth
|
|
# var stmts/eax: (handle list stmt) = block->statements
|
|
8b/-> *(esi+4) 0/r32/eax # Block-stmts
|
|
#
|
|
{
|
|
$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: (handle var)
|
|
8b/-> *(esi+8) 1/r32/ecx # Block-var
|
|
#
|
|
(write-buffered *(ebp+8) *ecx) # Var-name
|
|
(write-buffered *(ebp+8) ":loop:\n")
|
|
ff 0/subop/increment *Curr-block-depth
|
|
(push *(ebp+0x10) %ecx)
|
|
(emit-subx-stmt-list *(ebp+8) %eax *(ebp+0x10))
|
|
(pop *(ebp+0x10)) # => eax
|
|
ff 1/subop/decrement *Curr-block-depth
|
|
(emit-indent *(ebp+8) *Curr-block-depth)
|
|
(write-buffered *(ebp+8) "}\n")
|
|
(write-buffered *(ebp+8) *ecx) # Var-name
|
|
(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
|
|
# For each operation, put variants with hard-coded registers before flexible ones.
|
|
#
|
|
# Idea for a notation to simplify such definitions:
|
|
# _Primitive-increment-eax:
|
|
# 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 # Tree-left
|
|
# 0 0 # 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:
|
|
# - increment/decrement
|
|
_Primitive-increment-eax:
|
|
# 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_increment_eax/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-increment-ecx/imm32/next
|
|
_string-increment:
|
|
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_increment_eax:
|
|
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
|
|
_Primitive-increment-ecx:
|
|
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_increment_ecx/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-increment-edx/imm32/next
|
|
_string_increment_ecx:
|
|
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
|
|
_Primitive-increment-edx:
|
|
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_increment_edx/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-increment-ebx/imm32/next
|
|
_string_increment_edx:
|
|
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
|
|
_Primitive-increment-ebx:
|
|
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_increment_ebx/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-increment-esi/imm32/next
|
|
_string_increment_ebx:
|
|
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
|
|
_Primitive-increment-esi:
|
|
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_increment_esi/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-increment-edi/imm32/next
|
|
_string_increment_esi:
|
|
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
|
|
_Primitive-increment-edi:
|
|
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_increment_edi/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-decrement-eax/imm32/next
|
|
_string_increment_edi:
|
|
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
|
|
_Primitive-decrement-eax:
|
|
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_decrement_eax/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-decrement-ecx/imm32/next
|
|
_string-decrement:
|
|
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_decrement_eax:
|
|
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
|
|
_Primitive-decrement-ecx:
|
|
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_decrement_ecx/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-decrement-edx/imm32/next
|
|
_string_decrement_ecx:
|
|
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
|
|
_Primitive-decrement-edx:
|
|
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_decrement_edx/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-decrement-ebx/imm32/next
|
|
_string_decrement_edx:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# "4a/decrement-edx"
|
|
0x10/imm32/size
|
|
0x34/4 0x3a/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
|
|
_Primitive-decrement-ebx:
|
|
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_decrement_ebx/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-decrement-esi/imm32/next
|
|
_string_decrement_ebx:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# "4b/decrement-ebx"
|
|
0x10/imm32/size
|
|
0x34/4 0x3b/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
|
|
_Primitive-decrement-esi:
|
|
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_decrement_esi/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-decrement-edi/imm32/next
|
|
_string_decrement_esi:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# "4e/decrement-esi"
|
|
0x10/imm32/size
|
|
0x34/4 0x3e/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
|
|
_Primitive-decrement-edi:
|
|
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_decrement_edi/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-increment-mem/imm32/next
|
|
_string_decrement_edi:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# "4f/decrement-edi"
|
|
0x10/imm32/size
|
|
0x34/4 0x3f/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
|
|
_Primitive-increment-mem:
|
|
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-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-increment-reg/imm32/next
|
|
_string_ff_subop_increment:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# "ff 0/subop/increment"
|
|
0x14/imm32/size
|
|
0x66/f 0x66/f 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
|
|
_Primitive-increment-reg:
|
|
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-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-decrement-mem/imm32/next
|
|
_Primitive-decrement-mem:
|
|
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-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-decrement-reg/imm32/next
|
|
_string_ff_subop_decrement:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# "ff 1/subop/decrement"
|
|
0x14/imm32/size
|
|
0x66/f 0x66/f 0x31/1 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
|
|
_Primitive-decrement-reg:
|
|
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-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-add-to-eax/imm32/next
|
|
# - add
|
|
_Primitive-add-to-eax:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var/eax <- add lit => 05/add-to-eax lit/imm32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"05/add-to-eax"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
1/imm32/imm32-is-first-inout
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-add-reg-to-reg/imm32/next
|
|
_Primitive-add-reg-to-reg:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"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-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-add-reg-to-mem/imm32/next
|
|
_Primitive-add-reg-to-mem:
|
|
# add-to var1 var2/reg => 01/add-to var1 var2/r32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"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-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-add-mem-to-reg/imm32/next
|
|
_Primitive-add-mem-to-reg:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var1/reg <- add var2 => 03/add var2/rm32 var1/r32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"03/add"/imm32/subx-name
|
|
1/imm32/rm32-is-first-inout
|
|
3/imm32/r32-is-first-output
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-add-lit-to-reg/imm32/next
|
|
_Primitive-add-lit-to-reg:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"81 0/subop/add"/imm32/subx-name
|
|
3/imm32/rm32-is-first-output
|
|
0/imm32/no-r32
|
|
1/imm32/imm32-is-first-inout
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-add-lit-to-mem/imm32/next
|
|
_Primitive-add-lit-to-mem:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"81 0/subop/add"/imm32/subx-name
|
|
1/imm32/rm32-is-first-inout
|
|
0/imm32/no-r32
|
|
2/imm32/imm32-is-second-inout
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-subtract-from-eax/imm32/next
|
|
# - subtract
|
|
_Primitive-subtract-from-eax:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"2d/subtract-from-eax"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
1/imm32/imm32-is-first-inout
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-subtract-reg-from-reg/imm32/next
|
|
_Primitive-subtract-reg-from-reg:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"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-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-subtract-reg-from-mem/imm32/next
|
|
_Primitive-subtract-reg-from-mem:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"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-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-subtract-mem-from-reg/imm32/next
|
|
_Primitive-subtract-mem-from-reg:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"2b/subtract"/imm32/subx-name
|
|
1/imm32/rm32-is-first-inout
|
|
3/imm32/r32-is-first-output
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-subtract-lit-from-reg/imm32/next
|
|
_Primitive-subtract-lit-from-reg:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"81 5/subop/subtract"/imm32/subx-name
|
|
3/imm32/rm32-is-first-output
|
|
0/imm32/no-r32
|
|
1/imm32/imm32-is-first-inout
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
_Primitive-subtract-lit-from-mem/imm32/next
|
|
_Primitive-subtract-lit-from-mem:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"81 5/subop/subtract"/imm32/subx-name
|
|
1/imm32/rm32-is-first-inout
|
|
0/imm32/no-r32
|
|
2/imm32/imm32-is-first-inout
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-and-with-eax/imm32/next
|
|
# - and
|
|
_Primitive-and-with-eax:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var/eax <- and lit => 25/and-with-eax lit/imm32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"25/and-with-eax"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
1/imm32/imm32-is-first-inout
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-and-reg-with-reg/imm32/next
|
|
_Primitive-and-reg-with-reg:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"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-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-and-reg-with-mem/imm32/next
|
|
_Primitive-and-reg-with-mem:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# and-with var1 var2/reg => 21/and-with var1 var2/r32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"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-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-and-mem-with-reg/imm32/next
|
|
_Primitive-and-mem-with-reg:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var1/reg <- and var2 => 23/and var2/rm32 var1/r32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"23/and"/imm32/subx-name
|
|
1/imm32/rm32-is-first-inout
|
|
3/imm32/r32-is-first-output
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-and-lit-with-reg/imm32/next
|
|
_Primitive-and-lit-with-reg:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"81 4/subop/and"/imm32/subx-name
|
|
3/imm32/rm32-is-first-output
|
|
0/imm32/no-r32
|
|
1/imm32/imm32-is-first-inout
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-and-lit-with-mem/imm32/next
|
|
_Primitive-and-lit-with-mem:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"81 4/subop/and"/imm32/subx-name
|
|
1/imm32/rm32-is-first-inout
|
|
0/imm32/no-r32
|
|
2/imm32/imm32-is-first-inout
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-or-with-eax/imm32/next
|
|
# - or
|
|
_Primitive-or-with-eax:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var/eax <- or lit => 0d/or-with-eax lit/imm32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0d/or-with-eax"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
1/imm32/imm32-is-first-inout
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-or-reg-with-reg/imm32/next
|
|
_Primitive-or-reg-with-reg:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"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-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-or-reg-with-mem/imm32/next
|
|
_Primitive-or-reg-with-mem:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# or-with var1 var2/reg => 09/or-with var1 var2/r32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"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-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-or-mem-with-reg/imm32/next
|
|
_Primitive-or-mem-with-reg:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var1/reg <- or var2 => 0b/or var2/rm32 var1/r32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0b/or"/imm32/subx-name
|
|
1/imm32/rm32-is-first-inout
|
|
3/imm32/r32-is-first-output
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-or-lit-with-reg/imm32/next
|
|
_Primitive-or-lit-with-reg:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"81 1/subop/or"/imm32/subx-name
|
|
3/imm32/rm32-is-first-output
|
|
0/imm32/no-r32
|
|
1/imm32/imm32-is-first-inout
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-or-lit-with-mem/imm32/next
|
|
_Primitive-or-lit-with-mem:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"81 1/subop/or"/imm32/subx-name
|
|
1/imm32/rm32-is-first-inout
|
|
0/imm32/no-r32
|
|
2/imm32/imm32-is-second-inout
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-xor-with-eax/imm32/next
|
|
# - xor
|
|
_Primitive-xor-with-eax:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var/eax <- xor lit => 35/xor-with-eax lit/imm32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"35/xor-with-eax"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
1/imm32/imm32-is-first-inout
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-xor-reg-with-reg/imm32/next
|
|
_Primitive-xor-reg-with-reg:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"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-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-xor-reg-with-mem/imm32/next
|
|
_Primitive-xor-reg-with-mem:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# xor-with var1 var2/reg => 31/xor-with var1 var2/r32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"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-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-xor-mem-with-reg/imm32/next
|
|
_Primitive-xor-mem-with-reg:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"33/xor"/imm32/subx-name
|
|
1/imm32/rm32-is-first-inout
|
|
3/imm32/r32-is-first-output
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-xor-lit-with-reg/imm32/next
|
|
_Primitive-xor-lit-with-reg:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"81 6/subop/xor"/imm32/subx-name
|
|
3/imm32/rm32-is-first-output
|
|
0/imm32/no-r32
|
|
1/imm32/imm32-is-first-inout
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-xor-lit-with-mem/imm32/next
|
|
_Primitive-xor-lit-with-mem:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"81 6/subop/xor"/imm32/subx-name
|
|
1/imm32/rm32-is-first-inout
|
|
0/imm32/no-r32
|
|
2/imm32/imm32-is-first-inout
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-copy-to-eax/imm32/next
|
|
# - copy
|
|
_Primitive-copy-to-eax:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var/eax <- copy lit => b8/copy-to-eax lit/imm32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"b8/copy-to-eax"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
1/imm32/imm32-is-first-inout
|
|
0/imm32/no-disp32
|
|
1/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-copy-to-ecx/imm32/next
|
|
_Primitive-copy-to-ecx:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var/ecx <- copy lit => b9/copy-to-ecx lit/imm32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"b9/copy-to-ecx"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
1/imm32/imm32-is-first-inout
|
|
0/imm32/no-disp32
|
|
1/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-copy-to-edx/imm32/next
|
|
_Primitive-copy-to-edx:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var/edx <- copy lit => ba/copy-to-edx lit/imm32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"ba/copy-to-edx"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
1/imm32/imm32-is-first-inout
|
|
0/imm32/no-disp32
|
|
1/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-copy-to-ebx/imm32/next
|
|
_Primitive-copy-to-ebx:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var/ebx <- copy lit => bb/copy-to-ebx lit/imm32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"bb/copy-to-ebx"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
1/imm32/imm32-is-first-inout
|
|
0/imm32/no-disp32
|
|
1/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-copy-to-esi/imm32/next
|
|
_Primitive-copy-to-esi:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var/esi <- copy lit => be/copy-to-esi lit/imm32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"be/copy-to-esi"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
1/imm32/imm32-is-first-inout
|
|
0/imm32/no-disp32
|
|
1/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-copy-to-edi/imm32/next
|
|
_Primitive-copy-to-edi:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var/edi <- copy lit => bf/copy-to-edi lit/imm32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"bf/copy-to-edi"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
1/imm32/imm32-is-first-inout
|
|
0/imm32/no-disp32
|
|
1/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-copy-reg-to-reg/imm32/next
|
|
_Primitive-copy-reg-to-reg:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var1/reg <- copy var2/reg => 89/<- var1/rm32 var2/r32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"89/<-"/imm32/subx-name
|
|
3/imm32/rm32-is-first-output
|
|
1/imm32/r32-is-first-inout
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
1/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-copy-reg-to-mem/imm32/next
|
|
_Primitive-copy-reg-to-mem:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# copy-to var1 var2/reg => 89/<- var1 var2/r32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"89/<-"/imm32/subx-name
|
|
1/imm32/rm32-is-first-inout
|
|
2/imm32/r32-is-second-inout
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
1/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-copy-mem-to-reg/imm32/next
|
|
_Primitive-copy-mem-to-reg:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var1/reg <- copy var2 => 8b/-> var2/rm32 var1/r32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"8b/->"/imm32/subx-name
|
|
1/imm32/rm32-is-first-inout
|
|
3/imm32/r32-is-first-output
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
1/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-copy-lit-to-reg/imm32/next
|
|
_Primitive-copy-lit-to-reg:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"c7 0/subop/copy"/imm32/subx-name
|
|
3/imm32/rm32-is-first-output
|
|
0/imm32/no-r32
|
|
1/imm32/imm32-is-first-inout
|
|
0/imm32/no-disp32
|
|
1/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-copy-lit-to-mem/imm32/next
|
|
_Primitive-copy-lit-to-mem:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"c7 0/subop/copy"/imm32/subx-name
|
|
1/imm32/rm32-is-first-inout
|
|
0/imm32/no-r32
|
|
2/imm32/imm32-is-first-inout
|
|
0/imm32/no-disp32
|
|
1/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-address/imm32/next
|
|
# - address
|
|
_Primitive-address:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var1/reg <- address var2 => 8d/copy-address var2/rm32 var1/r32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"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-disp32
|
|
1/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-compare-mem-with-reg/imm32/next
|
|
# - compare
|
|
_Primitive-compare-mem-with-reg:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# compare var1 var2/reg => 39/compare var1/rm32 var2/r32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"39/compare->"/imm32/subx-name
|
|
1/imm32/rm32-is-first-inout
|
|
2/imm32/r32-is-second-inout
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-compare-reg-with-mem/imm32/next
|
|
_Primitive-compare-reg-with-mem:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# compare var1/reg var2 => 3b/compare<- var2/rm32 var1/r32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"3b/compare<-"/imm32/subx-name
|
|
2/imm32/rm32-is-second-inout
|
|
1/imm32/r32-is-first-inout
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-compare-eax-with-literal/imm32/next
|
|
_Primitive-compare-eax-with-literal:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# compare var1/eax n => 3d/compare-eax-with n/imm32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"3d/compare-eax-with"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
2/imm32/imm32-is-second-inout
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-compare-reg-with-literal/imm32/next
|
|
_Primitive-compare-reg-with-literal:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# compare var1/reg n => 81 7/subop/compare %reg n/imm32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"81 7/subop/compare"/imm32/subx-name
|
|
1/imm32/rm32-is-first-inout
|
|
0/imm32/no-r32
|
|
2/imm32/imm32-is-second-inout
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-compare-mem-with-literal/imm32/next
|
|
_Primitive-compare-mem-with-literal:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# compare var1 n => 81 7/subop/compare *(ebp+___) n/imm32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"81 7/subop/compare"/imm32/subx-name
|
|
1/imm32/rm32-is-first-inout
|
|
0/imm32/no-r32
|
|
2/imm32/imm32-is-second-inout
|
|
0/imm32/no-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-multiply-reg-by-mem/imm32/next
|
|
# - multiply
|
|
_Primitive-multiply-reg-by-mem:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
# var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"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-disp32
|
|
0/imm32/output-is-write-only
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-break-if-addr</imm32/next
|
|
# - branches
|
|
_Primitive-break-if-addr<:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 82/jump-if-addr< break/disp32"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-break-if-addr>=/imm32/next
|
|
_Primitive-break-if-addr>=:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 83/jump-if-addr>= break/disp32"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-break-if-=/imm32/next
|
|
_Primitive-break-if-=:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 84/jump-if-= break/disp32"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-break-if-!=/imm32/next
|
|
_Primitive-break-if-!=:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 85/jump-if-!= break/disp32"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-break-if-addr<=/imm32/next
|
|
_Primitive-break-if-addr<=:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 86/jump-if-addr<= break/disp32"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-break-if-addr>/imm32/next
|
|
_Primitive-break-if-addr>:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 87/jump-if-addr> break/disp32"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-break-if-</imm32/next
|
|
_Primitive-break-if-<:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 8c/jump-if-< break/disp32"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-break-if->=/imm32/next
|
|
_Primitive-break-if->=:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 8d/jump-if->= break/disp32"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-break-if-<=/imm32/next
|
|
_Primitive-break-if-<=:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 8e/jump-if-<= break/disp32"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-break-if->/imm32/next
|
|
_Primitive-break-if->:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 8f/jump-if-> break/disp32"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-break/imm32/next
|
|
_Primitive-break:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"break"/imm32/name
|
|
0/imm32/no-inouts
|
|
0/imm32/no-inouts
|
|
0/imm32/no-outputs
|
|
0/imm32/no-outputs
|
|
0x11/imm32/alloc-id:fake
|
|
"e9/jump break/disp32"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-loop-if-addr</imm32/next
|
|
_Primitive-loop-if-addr<:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 82/jump-if-addr< loop/disp32"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-loop-if-addr>=/imm32/next
|
|
_Primitive-loop-if-addr>=:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 83/jump-if-addr>= loop/disp32"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-loop-if-=/imm32/next
|
|
_Primitive-loop-if-=:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 84/jump-if-= loop/disp32"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-loop-if-!=/imm32/next
|
|
_Primitive-loop-if-!=:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 85/jump-if-!= loop/disp32"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-loop-if-addr<=/imm32/next
|
|
_Primitive-loop-if-addr<=:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 86/jump-if-addr<= loop/disp32"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-loop-if-addr>/imm32/next
|
|
_Primitive-loop-if-addr>:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 87/jump-if-addr> loop/disp32"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-loop-if-</imm32/next
|
|
_Primitive-loop-if-<:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 8c/jump-if-< loop/disp32"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-loop-if->=/imm32/next
|
|
_Primitive-loop-if->=:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 8d/jump-if->= loop/disp32"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-loop-if-<=/imm32/next
|
|
_Primitive-loop-if-<=:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 8e/jump-if-<= loop/disp32"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-loop-if->/imm32/next
|
|
_Primitive-loop-if->:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 8f/jump-if-> loop/disp32"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-loop/imm32/next # we probably don't need an unconditional break
|
|
_Primitive-loop:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"loop"/imm32/name
|
|
0/imm32/no-inouts
|
|
0/imm32/no-inouts
|
|
0/imm32/no-outputs
|
|
0/imm32/no-outputs
|
|
0x11/imm32/alloc-id:fake
|
|
"e9/jump loop/disp32"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
0/imm32/no-disp32
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-break-if-addr<-named/imm32/next
|
|
# - branches to named blocks
|
|
_Primitive-break-if-addr<-named:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 82/jump-if-addr<"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
1/imm32/disp32-is-first-inout
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-break-if-addr>=-named/imm32/next
|
|
_Primitive-break-if-addr>=-named:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 83/jump-if-addr>="/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
1/imm32/disp32-is-first-inout
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-break-if-=-named/imm32/next
|
|
_Primitive-break-if-=-named:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 84/jump-if-="/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
1/imm32/disp32-is-first-inout
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-break-if-!=-named/imm32/next
|
|
_Primitive-break-if-!=-named:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 85/jump-if-!="/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
1/imm32/disp32-is-first-inout
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-break-if-addr<=-named/imm32/next
|
|
_Primitive-break-if-addr<=-named:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 86/jump-if-addr<="/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
1/imm32/disp32-is-first-inout
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-break-if-addr>-named/imm32/next
|
|
_Primitive-break-if-addr>-named:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 87/jump-if-addr>"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
1/imm32/disp32-is-first-inout
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-break-if-<-named/imm32/next
|
|
_Primitive-break-if-<-named:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 8c/jump-if-<"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
1/imm32/disp32-is-first-inout
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-break-if->=-named/imm32/next
|
|
_Primitive-break-if->=-named:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 8d/jump-if->="/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
1/imm32/disp32-is-first-inout
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-break-if-<=-named/imm32/next
|
|
_Primitive-break-if-<=-named:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 8e/jump-if-<="/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
1/imm32/disp32-is-first-inout
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-break-if->-named/imm32/next
|
|
_Primitive-break-if->-named:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 8f/jump-if->"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
1/imm32/disp32-is-first-inout
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-break-named/imm32/next
|
|
_Primitive-break-named:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"e9/jump"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
1/imm32/disp32-is-first-inout
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-loop-if-addr<-named/imm32/next
|
|
_Primitive-loop-if-addr<-named:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 82/jump-if-addr<"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
1/imm32/disp32-is-first-inout
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-loop-if-addr>=-named/imm32/next
|
|
_Primitive-loop-if-addr>=-named:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 83/jump-if-addr>="/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
1/imm32/disp32-is-first-inout
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-loop-if-=-named/imm32/next
|
|
_Primitive-loop-if-=-named:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 84/jump-if-="/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
1/imm32/disp32-is-first-inout
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-loop-if-!=-named/imm32/next
|
|
_Primitive-loop-if-!=-named:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 85/jump-if-!="/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
1/imm32/disp32-is-first-inout
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-loop-if-addr<=-named/imm32/next
|
|
_Primitive-loop-if-addr<=-named:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 86/jump-if-addr<="/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
1/imm32/disp32-is-first-inout
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-loop-if-addr>-named/imm32/next
|
|
_Primitive-loop-if-addr>-named:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 87/jump-if-addr>"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
1/imm32/disp32-is-first-inout
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-loop-if-<-named/imm32/next
|
|
_Primitive-loop-if-<-named:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 8c/jump-if-<"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
1/imm32/disp32-is-first-inout
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-loop-if->=-named/imm32/next
|
|
_Primitive-loop-if->=-named:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 8d/jump-if->="/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
1/imm32/disp32-is-first-inout
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-loop-if-<=-named/imm32/next
|
|
_Primitive-loop-if-<=-named:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 8e/jump-if-<="/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
1/imm32/disp32-is-first-inout
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-loop-if->-named/imm32/next
|
|
_Primitive-loop-if->-named:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"0f 8f/jump-if->"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
1/imm32/disp32-is-first-inout
|
|
0/imm32/no-output
|
|
0x11/imm32/alloc-id:fake
|
|
_Primitive-loop-named/imm32/next # we probably don't need an unconditional break
|
|
_Primitive-loop-named:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
0x11/imm32/alloc-id:fake
|
|
"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
|
|
"e9/jump"/imm32/subx-name
|
|
0/imm32/no-rm32
|
|
0/imm32/no-r32
|
|
0/imm32/no-imm32
|
|
1/imm32/disp32-is-first-inout
|
|
0/imm32/no-output
|
|
0/imm32/next
|
|
0/imm32/next
|
|
|
|
Single-int-var-in-mem:
|
|
Int-var-in-mem/imm32
|
|
0/imm32/next
|
|
|
|
Int-var-in-mem:
|
|
"arg1"/imm32/name
|
|
Type-int/imm32
|
|
1/imm32/some-block-depth
|
|
1/imm32/some-stack-offset
|
|
0/imm32/no-register
|
|
|
|
Two-args-int-stack-int-reg:
|
|
Int-var-in-mem/imm32
|
|
Single-int-var-in-some-register/imm32/next
|
|
|
|
Two-args-int-reg-int-stack:
|
|
Int-var-in-some-register/imm32
|
|
Single-int-var-in-mem/imm32/next
|
|
|
|
Two-args-int-eax-int-literal:
|
|
Int-var-in-eax/imm32
|
|
Single-lit-var/imm32/next
|
|
|
|
Int-var-and-literal:
|
|
Int-var-in-mem/imm32
|
|
Single-lit-var/imm32/next
|
|
|
|
Int-var-in-register-and-literal:
|
|
Int-var-in-some-register/imm32
|
|
Single-lit-var/imm32/next
|
|
|
|
Single-int-var-in-some-register:
|
|
Int-var-in-some-register/imm32
|
|
0/imm32/next
|
|
|
|
Single-addr-var-in-some-register:
|
|
Addr-var-in-some-register/imm32
|
|
0/imm32/next
|
|
|
|
Int-var-in-some-register:
|
|
"arg1"/imm32/name
|
|
Type-int/imm32
|
|
1/imm32/some-block-depth
|
|
0/imm32/no-stack-offset
|
|
Any-register/imm32
|
|
|
|
Addr-var-in-some-register:
|
|
"arg1"/imm32/name
|
|
Type-addr/imm32
|
|
1/imm32/some-block-depth
|
|
0/imm32/no-stack-offset
|
|
Any-register/imm32
|
|
|
|
Single-int-var-in-eax:
|
|
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
|
|
$Register-eax/imm32
|
|
|
|
Single-int-var-in-ecx:
|
|
Int-var-in-ecx/imm32
|
|
0/imm32/next
|
|
|
|
Int-var-in-ecx:
|
|
"arg1"/imm32/name
|
|
Type-int/imm32
|
|
1/imm32/some-block-depth
|
|
0/imm32/no-stack-offset
|
|
"ecx"/imm32/register
|
|
|
|
Single-int-var-in-edx:
|
|
Int-var-in-edx/imm32
|
|
0/imm32/next
|
|
|
|
Int-var-in-edx:
|
|
"arg1"/imm32/name
|
|
Type-int/imm32
|
|
1/imm32/some-block-depth
|
|
0/imm32/no-stack-offset
|
|
"edx"/imm32/register
|
|
|
|
Single-int-var-in-ebx:
|
|
Int-var-in-ebx/imm32
|
|
0/imm32/next
|
|
|
|
Int-var-in-ebx:
|
|
"arg1"/imm32/name
|
|
Type-int/imm32
|
|
1/imm32/some-block-depth
|
|
0/imm32/no-stack-offset
|
|
"ebx"/imm32/register
|
|
|
|
Single-int-var-in-esi:
|
|
Int-var-in-esi/imm32
|
|
0/imm32/next
|
|
|
|
Int-var-in-esi:
|
|
"arg1"/imm32/name
|
|
Type-int/imm32
|
|
1/imm32/some-block-depth
|
|
0/imm32/no-stack-offset
|
|
"esi"/imm32/register
|
|
|
|
Single-int-var-in-edi:
|
|
Int-var-in-edi/imm32
|
|
0/imm32/next
|
|
|
|
Int-var-in-edi:
|
|
"arg1"/imm32/name
|
|
Type-int/imm32
|
|
1/imm32/some-block-depth
|
|
0/imm32/no-stack-offset
|
|
"edi"/imm32/register
|
|
|
|
Single-lit-var:
|
|
Lit-var/imm32
|
|
0/imm32/next
|
|
|
|
Lit-var:
|
|
"literal"/imm32/name
|
|
Type-literal/imm32
|
|
1/imm32/some-block-depth
|
|
0/imm32/no-stack-offset
|
|
0/imm32/no-register
|
|
|
|
Type-int:
|
|
0x11/imm32/alloc-id:fake:payload
|
|
1/imm32/left-is-atom
|
|
1/imm32/value:int
|
|
0/imm32/left:unused
|
|
0/imm32/right:null
|
|
0/imm32/right:null
|
|
|
|
Type-literal:
|
|
1/imm32/left-is-atom
|
|
0/imm32/left/literal
|
|
0/imm32/right/null
|
|
|
|
Type-addr:
|
|
1/imm32/left-is-atom
|
|
2/imm32/left/addr
|
|
0/imm32/right/null
|
|
|
|
== code
|
|
emit-subx-primitive: # out: (addr buffered-file), stmt: (addr stmt), primitive: (addr primitive)
|
|
# . 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)) # out, Primitive-subx-rm32, stmt
|
|
# emit r32 if necessary
|
|
(emit-subx-r32 *(ebp+8) *(ecx+0x24) *(ebp+0xc)) # out, Primitive-subx-r32, stmt
|
|
# emit imm32 if necessary
|
|
(emit-subx-imm32 *(ebp+8) *(ecx+0x28) *(ebp+0xc)) # out, Primitive-subx-imm32, stmt
|
|
# emit disp32 if necessary
|
|
(emit-subx-disp32 *(ebp+8) *(ecx+0x2c) *(ebp+0xc)) # out, Primitive-subx-disp32, stmt
|
|
(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)
|
|
# . 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: (handle var)
|
|
(get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # => 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 -> 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 Stderr "invalid arg-location ")
|
|
(print-int32-buffered Stderr %eax)
|
|
(write-buffered Stderr Newline)
|
|
(flush Stderr)
|
|
# . syscall(exit, 1)
|
|
bb/copy-to-ebx 1/imm32
|
|
b8/copy-to-eax 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# 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 (location == 0) return
|
|
81 7/subop/compare *(ebp+0xc) 0/imm32
|
|
0f 84/jump-if-= $emit-subx-r32:end/disp32
|
|
# var v/eax: (handle var)
|
|
(get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # => eax
|
|
8b/-> *eax 0/r32/eax # Stmt-var-value
|
|
(maybe-get Registers *(eax+0x10) 0xc) # Var-register => eax: (addr register-index)
|
|
(write-buffered *(ebp+8) Space)
|
|
(print-int32-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-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 (location == 0) return
|
|
81 7/subop/compare *(ebp+0xc) 0/imm32
|
|
74/jump-if-= $emit-subx-imm32:end/disp8
|
|
# var v/eax: (handle var)
|
|
(get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # => eax
|
|
8b/-> *eax 0/r32/eax # Stmt-var-value
|
|
(write-buffered *(ebp+8) Space)
|
|
(write-buffered *(ebp+8) *eax) # Var-name
|
|
(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-disp32: # 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 (location == 0) return
|
|
81 7/subop/compare *(ebp+0xc) 0/imm32
|
|
0f 84/jump-if-= $emit-subx-disp32:end/disp32
|
|
# var v/eax: (handle var)
|
|
(get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # => eax
|
|
8b/-> *eax 0/r32/eax # Stmt-var-value
|
|
(write-buffered *(ebp+8) Space)
|
|
(write-buffered *(ebp+8) *eax) # Var-name
|
|
# hack: if instruction operation starts with "break", emit ":break"
|
|
# var name/ecx: (addr array byte) = stmt->operation
|
|
8b/-> *(ebp+0x10) 0/r32/eax
|
|
8b/-> *(eax+4) 1/r32/ecx
|
|
{
|
|
(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/ecx: (addr stmt-var) = lookup(stmt->inouts)
|
|
(lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax
|
|
89/<- %ecx 0/r32/eax
|
|
{
|
|
# if (curr == null) break
|
|
81 7/subop/compare %ecx 0/imm32
|
|
74/jump-if-= break/disp8
|
|
#
|
|
(emit-subx-call-operand *(ebp+8) %ecx)
|
|
# curr = curr->next
|
|
8b/-> *(ecx+4) 1/r32/ecx # Stmt-var-next
|
|
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 # Tree-left
|
|
75/jump-if-!= break/disp8
|
|
$emit-subx-call-operand:literal:
|
|
(write-buffered *(ebp+8) Space)
|
|
(write-buffered *(ebp+8) *esi)
|
|
}
|
|
$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
|
|
# 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+0x10)) # Var-register
|
|
(write-buffered *(ebp+8) "+")
|
|
(print-int32-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+0xc) 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+")
|
|
(print-int32-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+")
|
|
(print-int32-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
|
|
0f 84/jump-if-= break/disp32
|
|
# 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+0x34) *(ecx+0x38)) # 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
|
|
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 (var->type != prim-var->type) return false
|
|
# . var vtype/ebx: (addr tree type-id) = lookup(var->type)
|
|
(lookup *(esi+8) *(esi+0xc)) # Var-type Var-type => eax
|
|
89/<- %ebx 0/r32/eax
|
|
# . var ptype/eax: (addr tree type-id) = lookup(prim-var->type)
|
|
(lookup *(edi+8) *(edi+0xc)) # Var-type Var-type => eax
|
|
(subx-type-equal? %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
|
|
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
|
|
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
|
|
# 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
|
|
# if string contents aren't equal, return false
|
|
(string-equal? %ecx %ebx) # => eax
|
|
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
|
|
|
|
subx-type-equal?: # a: (addr tree type-id), b: (addr tree type-id) -> result/eax: boolean
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
# . save registers
|
|
51/push-ecx
|
|
# var alit/ecx: boolean = is-literal-type?(a)
|
|
(is-simple-mu-type? *(ebp+8) 0) # => eax
|
|
89/<- %ecx 0/r32/eax
|
|
# var blit/eax: boolean = is-literal-type?(b)
|
|
(is-simple-mu-type? *(ebp+0xc) 0) # => eax
|
|
# return alit == blit
|
|
39/compare %eax 1/r32/ecx
|
|
0f 94/set-byte-if-= %al
|
|
81 4/subop/and %eax 0xff/imm32
|
|
$subx-type-equal?: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 tree type-id), 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 # 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
|
|
|
|
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: (handle tree type-id) = 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: (handle 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: (handle 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/output-is-write-only
|
|
68/push 0/imm32/no-disp32
|
|
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)
|
|
(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: (handle tree type-id) = 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: (handle 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: (handle 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: (handle 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: (handle 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: primitive
|
|
68/push 0/imm32/next
|
|
68/push 0/imm32/next
|
|
68/push 0/imm32/output-is-write-only
|
|
68/push 0/imm32/no-disp32
|
|
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)
|
|
(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: (handle tree type-id) = 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: (handle 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: (handle 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: (handle 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: (handle 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: (handle primitive)
|
|
68/push 0/imm32/next
|
|
68/push 0/imm32/next
|
|
68/push 0/imm32/output-is-write-only
|
|
68/push 0/imm32/no-disp32
|
|
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/output-is-write-only
|
|
68/push 0/imm32/no-disp32
|
|
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)
|
|
(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: (handle tree type-id) = 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: (handle 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: (handle 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: (handle 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: (handle 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: (handle primitive)
|
|
68/push 0/imm32/next
|
|
68/push 0/imm32/next
|
|
68/push 0/imm32/output-is-write-only
|
|
68/push 0/imm32/no-disp32
|
|
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/output-is-write-only
|
|
68/push 0/imm32/no-disp32
|
|
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)
|
|
(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: (handle tree type-id) = 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: (handle 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: (handle 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)
|
|
(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)
|
|
# var type/ecx: (handle tree type-id) = int
|
|
68/push 0/imm32/right/null
|
|
68/push 1/imm32/left/int
|
|
68/push 1/imm32/is-atom
|
|
89/<- %ecx 4/r32/esp
|
|
# var var-var1/ecx: var in eax
|
|
68/push "eax"/imm32/register
|
|
68/push 0/imm32/no-stack-offset
|
|
68/push 1/imm32/block-depth
|
|
51/push-ecx
|
|
68/push "var1"/imm32
|
|
89/<- %ecx 4/r32/esp
|
|
# var var-var2/edx: var in ecx
|
|
68/push "ecx"/imm32/register
|
|
68/push 0/imm32/no-stack-offset
|
|
68/push 1/imm32/block-depth
|
|
ff 6/subop/push *(ecx+4) # Var-type
|
|
68/push "var2"/imm32
|
|
89/<- %edx 4/r32/esp
|
|
# var inouts/esi: (handle stmt-var) = [var2]
|
|
68/push 0/imm32/is-deref:false
|
|
68/push 0/imm32/next
|
|
52/push-edx/var-var2
|
|
89/<- %esi 4/r32/esp
|
|
# var outputs/edi: (handle stmt-var) = [var1, var2]
|
|
68/push 0/imm32/is-deref:false
|
|
68/push 0/imm32/next
|
|
51/push-ecx/var-var1
|
|
89/<- %edi 4/r32/esp
|
|
# var stmt/esi: statement
|
|
68/push 0/imm32/next
|
|
57/push-edi/outputs
|
|
56/push-esi/inouts
|
|
68/push "add"/imm32/operation
|
|
68/push 1/imm32
|
|
89/<- %esi 4/r32/esp
|
|
# convert
|
|
c7 0/subop/copy *Curr-block-depth 0/imm32
|
|
(emit-subx-stmt _test-output-buffered-file %esi Primitives)
|
|
(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)
|
|
# var type/ecx: (handle tree type-id) = int
|
|
68/push 0/imm32/right/null
|
|
68/push 1/imm32/left/int
|
|
68/push 1/imm32/is-atom
|
|
89/<- %ecx 4/r32/esp
|
|
# var var-var1/ecx: var
|
|
68/push 0/imm32/no-register
|
|
68/push 8/imm32/stack-offset
|
|
68/push 1/imm32/block-depth
|
|
51/push-ecx
|
|
68/push "var1"/imm32
|
|
89/<- %ecx 4/r32/esp
|
|
# var var-var2/edx: var in ecx
|
|
68/push "ecx"/imm32/register
|
|
68/push 0/imm32/no-stack-offset
|
|
68/push 1/imm32/block-depth
|
|
ff 6/subop/push *(ecx+4) # Var-type
|
|
68/push "var2"/imm32
|
|
89/<- %edx 4/r32/esp
|
|
# var inouts/esi: (handle stmt-var) = [var2]
|
|
68/push 0/imm32/is-deref:false
|
|
68/push 0/imm32/next
|
|
52/push-edx/var-var2
|
|
89/<- %esi 4/r32/esp
|
|
# var inouts = (handle stmt-var) = [var1, var2]
|
|
56/push-esi/next
|
|
51/push-ecx/var-var1
|
|
89/<- %esi 4/r32/esp
|
|
# var stmt/esi: statement
|
|
68/push 0/imm32/next
|
|
68/push 0/imm32/no-outputs
|
|
56/push-esi/inouts
|
|
68/push "add-to"/imm32/operation
|
|
68/push 1/imm32
|
|
89/<- %esi 4/r32/esp
|
|
# convert
|
|
c7 0/subop/copy *Curr-block-depth 0/imm32
|
|
(emit-subx-stmt _test-output-buffered-file %esi Primitives)
|
|
(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)
|
|
# var type/ecx: (handle tree type-id) = int
|
|
68/push 0/imm32/right/null
|
|
68/push 1/imm32/left/int
|
|
68/push 1/imm32/is-atom
|
|
89/<- %ecx 4/r32/esp
|
|
# var var-var1/ecx: var in eax
|
|
68/push "eax"/imm32/register
|
|
68/push 0/imm32/no-stack-offset
|
|
68/push 1/imm32/block-depth
|
|
51/push-ecx
|
|
68/push "var1"/imm32
|
|
89/<- %ecx 4/r32/esp
|
|
# var var-var2/edx: var
|
|
68/push 0/imm32/no-register
|
|
68/push 8/imm32/stack-offset
|
|
68/push 1/imm32/block-depth
|
|
ff 6/subop/push *(ecx+4) # Var-type
|
|
68/push "var2"/imm32
|
|
89/<- %edx 4/r32/esp
|
|
# var inouts/esi: (handle stmt-var) = [var2]
|
|
68/push 0/imm32/is-deref:false
|
|
68/push 0/imm32/next
|
|
52/push-edx/var-var2
|
|
89/<- %esi 4/r32/esp
|
|
# var outputs/edi = (handle stmt-var) = [var1]
|
|
68/push 0/imm32/is-deref:false
|
|
68/push 0/imm32/next
|
|
51/push-ecx/var-var1
|
|
89/<- %edi 4/r32/esp
|
|
# var stmt/esi: statement
|
|
68/push 0/imm32/next
|
|
57/push-edi/outputs
|
|
56/push-esi/inouts
|
|
68/push "add"/imm32/operation
|
|
68/push 1/imm32
|
|
89/<- %esi 4/r32/esp
|
|
# convert
|
|
c7 0/subop/copy *Curr-block-depth 0/imm32
|
|
(emit-subx-stmt _test-output-buffered-file %esi Primitives)
|
|
(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)
|
|
# var type/ecx: (handle tree type-id) = int
|
|
68/push 0/imm32/right/null
|
|
68/push 1/imm32/left/int
|
|
68/push 1/imm32/is-atom
|
|
89/<- %ecx 4/r32/esp
|
|
# var var-var1/ecx: var in eax
|
|
68/push "eax"/imm32/register
|
|
68/push 0/imm32/no-stack-offset
|
|
68/push 1/imm32/block-depth
|
|
51/push-ecx
|
|
68/push "var1"/imm32
|
|
89/<- %ecx 4/r32/esp
|
|
# var type/edx: (handle tree type-id) = literal
|
|
68/push 0/imm32/right/null
|
|
68/push 0/imm32/left/literal
|
|
89/<- %edx 4/r32/esp
|
|
# var var-var2/edx: var literal
|
|
68/push 0/imm32/no-register
|
|
68/push 0/imm32/no-stack-offset
|
|
68/push 1/imm32/block-depth
|
|
52/push-edx
|
|
68/push "0x34"/imm32
|
|
89/<- %edx 4/r32/esp
|
|
# var inouts/esi: (handle stmt-var) = [var2]
|
|
68/push 0/imm32/is-deref:false
|
|
68/push 0/imm32/next
|
|
52/push-edx/var-var2
|
|
89/<- %esi 4/r32/esp
|
|
# var outputs/edi: (handle stmt-var) = [var1]
|
|
68/push 0/imm32/is-deref:false
|
|
68/push 0/imm32/next
|
|
51/push-ecx/var-var1
|
|
89/<- %edi 4/r32/esp
|
|
# var stmt/esi: statement
|
|
68/push 0/imm32/next
|
|
57/push-edi/outputs
|
|
56/push-esi/inouts
|
|
68/push "add"/imm32/operation
|
|
68/push 1/imm32
|
|
89/<- %esi 4/r32/esp
|
|
# convert
|
|
c7 0/subop/copy *Curr-block-depth 0/imm32
|
|
(emit-subx-stmt _test-output-buffered-file %esi Primitives)
|
|
(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)
|
|
# var type/ecx: (handle tree type-id) = int
|
|
68/push 0/imm32/right/null
|
|
68/push 1/imm32/left/int
|
|
68/push 1/imm32/is-atom
|
|
89/<- %ecx 4/r32/esp
|
|
# var var-var1/ecx: var in ecx
|
|
68/push "ecx"/imm32/register
|
|
68/push 0/imm32/no-stack-offset
|
|
68/push 1/imm32/block-depth
|
|
51/push-ecx
|
|
68/push "var1"/imm32
|
|
89/<- %ecx 4/r32/esp
|
|
# var type/edx: (handle tree type-id) = literal
|
|
68/push 0/imm32/right/null
|
|
68/push 0/imm32/left/literal
|
|
89/<- %edx 4/r32/esp
|
|
# var var-var2/edx: var literal
|
|
68/push 0/imm32/no-register
|
|
68/push 0/imm32/no-stack-offset
|
|
68/push 1/imm32/block-depth
|
|
52/push-edx
|
|
68/push "0x34"/imm32
|
|
89/<- %edx 4/r32/esp
|
|
# var inouts/esi: (handle stmt-var) = [var2]
|
|
68/push 0/imm32/is-deref:false
|
|
68/push 0/imm32/next
|
|
52/push-edx/var-var2
|
|
89/<- %esi 4/r32/esp
|
|
# var outputs/edi: (handle stmt-var) = [var1]
|
|
68/push 0/imm32/is-deref:false
|
|
68/push 0/imm32/next
|
|
51/push-ecx/var-var1
|
|
89/<- %edi 4/r32/esp
|
|
# var stmt/esi: statement
|
|
68/push 0/imm32/next
|
|
57/push-edi/outputs
|
|
56/push-esi/inouts
|
|
68/push "add"/imm32/operation
|
|
68/push 1/imm32
|
|
89/<- %esi 4/r32/esp
|
|
# convert
|
|
c7 0/subop/copy *Curr-block-depth 0/imm32
|
|
(emit-subx-stmt _test-output-buffered-file %esi Primitives)
|
|
(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)
|
|
# var type/ecx: (handle tree type-id) = int
|
|
68/push 0/imm32/right/null
|
|
68/push 1/imm32/left/int
|
|
68/push 1/imm32/is-atom
|
|
89/<- %ecx 4/r32/esp
|
|
# var var-var1/ecx: var
|
|
68/push 0/imm32/no-register
|
|
68/push 8/imm32/stack-offset
|
|
68/push 1/imm32/block-depth
|
|
51/push-ecx
|
|
68/push "var1"/imm32
|
|
89/<- %ecx 4/r32/esp
|
|
# var type/edx: (handle tree type-id) = literal
|
|
68/push 0/imm32/right/null
|
|
68/push 0/imm32/left/literal
|
|
89/<- %edx 4/r32/esp
|
|
# var var-var2/edx: var literal
|
|
68/push 0/imm32/no-register
|
|
68/push 0/imm32/no-stack-offset
|
|
68/push 1/imm32/block-depth
|
|
52/push-edx
|
|
68/push "0x34"/imm32
|
|
89/<- %edx 4/r32/esp
|
|
# var inouts/esi: (handle stmt-var) = [var2]
|
|
68/push 0/imm32/is-deref:false
|
|
68/push 0/imm32/next
|
|
52/push-edx/var-var2
|
|
89/<- %esi 4/r32/esp
|
|
# var inouts = (handle stmt-var) = [var1, var2]
|
|
68/push 0/imm32/is-deref:false
|
|
56/push-esi/next
|
|
51/push-ecx/var-var1
|
|
89/<- %esi 4/r32/esp
|
|
# var stmt/esi: statement
|
|
68/push 0/imm32/next
|
|
68/push 0/imm32/no-outputs
|
|
56/push-esi/inouts
|
|
68/push "add-to"/imm32/operation
|
|
68/push 1/imm32
|
|
89/<- %esi 4/r32/esp
|
|
# convert
|
|
c7 0/subop/copy *Curr-block-depth 0/imm32
|
|
(emit-subx-stmt _test-output-buffered-file %esi Primitives)
|
|
(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-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)
|
|
# var type/ecx: (handle tree type-id) = int
|
|
68/push 0/imm32/right/null
|
|
68/push 1/imm32/left/int
|
|
68/push 1/imm32/is-atom
|
|
89/<- %ecx 4/r32/esp
|
|
# var var-var2/ecx: var in eax
|
|
68/push "eax"/imm32/register
|
|
68/push 0/imm32/no-stack-offset
|
|
68/push 1/imm32/block-depth
|
|
51/push-ecx
|
|
68/push "var2"/imm32
|
|
89/<- %ecx 4/r32/esp
|
|
# var var-var1/edx: var
|
|
68/push 0/imm32/no-register
|
|
68/push 8/imm32/stack-offset
|
|
68/push 1/imm32/block-depth
|
|
ff 6/subop/push *(ecx+4) # Var-type
|
|
68/push "var1"/imm32
|
|
89/<- %edx 4/r32/esp
|
|
# var inouts/esi: (handle stmt-var) = [var2]
|
|
68/push 0/imm32/is-deref:false
|
|
68/push 0/imm32/next
|
|
51/push-ecx/var-var2
|
|
89/<- %esi 4/r32/esp
|
|
# inouts = [var1, var2]
|
|
68/push 0/imm32/is-deref:false
|
|
56/push-esi
|
|
52/push-edx/var-var1
|
|
89/<- %esi 4/r32/esp
|
|
# var stmt/esi: statement
|
|
68/push 0/imm32/next
|
|
68/push 0/imm32/no-outputs
|
|
56/push-esi/inouts
|
|
68/push "compare"/imm32/operation
|
|
68/push 1/imm32
|
|
89/<- %esi 4/r32/esp
|
|
# convert
|
|
c7 0/subop/copy *Curr-block-depth 0/imm32
|
|
(emit-subx-stmt _test-output-buffered-file %esi Primitives)
|
|
(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)
|
|
# var type/ecx: (handle tree type-id) = int
|
|
68/push 0/imm32/right/null
|
|
68/push 1/imm32/left/int
|
|
68/push 1/imm32/is-atom
|
|
89/<- %ecx 4/r32/esp
|
|
# var var-var1/ecx: var in eax
|
|
68/push "eax"/imm32/register
|
|
68/push 0/imm32/no-stack-offset
|
|
68/push 1/imm32/block-depth
|
|
51/push-ecx
|
|
68/push "var1"/imm32
|
|
89/<- %ecx 4/r32/esp
|
|
# var var-var2/edx: var
|
|
68/push 0/imm32/no-register
|
|
68/push 8/imm32/stack-offset
|
|
68/push 1/imm32/block-depth
|
|
ff 6/subop/push *(ecx+4) # Var-type
|
|
68/push "var2"/imm32
|
|
89/<- %edx 4/r32/esp
|
|
# var inouts/esi: (handle stmt-var) = [var2]
|
|
68/push 0/imm32/is-deref:false
|
|
68/push 0/imm32/next
|
|
52/push-edx/var-var2
|
|
89/<- %esi 4/r32/esp
|
|
# inouts = [var1, var2]
|
|
68/push 0/imm32/is-deref:false
|
|
56/push-esi
|
|
51/push-ecx/var-var1
|
|
89/<- %esi 4/r32/esp
|
|
# var stmt/esi: statement
|
|
68/push 0/imm32/next
|
|
68/push 0/imm32/no-outputs
|
|
56/push-esi/inouts
|
|
68/push "compare"/imm32/operation
|
|
68/push 1/imm32
|
|
89/<- %esi 4/r32/esp
|
|
# convert
|
|
c7 0/subop/copy *Curr-block-depth 0/imm32
|
|
(emit-subx-stmt _test-output-buffered-file %esi Primitives)
|
|
(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)
|
|
# var type/ecx: (handle tree type-id) = int
|
|
68/push 0/imm32/right/null
|
|
68/push 1/imm32/left/int
|
|
68/push 1/imm32/is-atom
|
|
89/<- %ecx 4/r32/esp
|
|
# var var-var1/ecx: var
|
|
68/push 0/imm32/no-register
|
|
68/push 8/imm32/stack-offset
|
|
68/push 1/imm32/block-depth
|
|
51/push-ecx
|
|
68/push "var1"/imm32
|
|
89/<- %ecx 4/r32/esp
|
|
# var type/edx: (handle tree type-id) = literal
|
|
68/push 0/imm32/right/null
|
|
68/push 0/imm32/left/literal
|
|
89/<- %edx 4/r32/esp
|
|
# var var-var2/edx: var literal
|
|
68/push 0/imm32/no-register
|
|
68/push 0/imm32/no-stack-offset
|
|
68/push 1/imm32/block-depth
|
|
52/push-edx
|
|
68/push "0x34"/imm32
|
|
89/<- %edx 4/r32/esp
|
|
# var inouts/esi: (handle stmt-var) = [var2]
|
|
68/push 0/imm32/is-deref:false
|
|
68/push 0/imm32/next
|
|
52/push-edx/var-var2
|
|
89/<- %esi 4/r32/esp
|
|
# inouts = [var1, var2]
|
|
68/push 0/imm32/is-deref:false
|
|
56/push-esi/next
|
|
51/push-ecx/var-var1
|
|
89/<- %esi 4/r32/esp
|
|
# var stmt/esi: statement
|
|
68/push 0/imm32/next
|
|
68/push 0/imm32/no-outputs
|
|
56/push-esi/inouts
|
|
68/push "compare"/imm32/operation
|
|
68/push 1/imm32
|
|
89/<- %esi 4/r32/esp
|
|
# convert
|
|
c7 0/subop/copy *Curr-block-depth 0/imm32
|
|
(emit-subx-stmt _test-output-buffered-file %esi Primitives)
|
|
(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)
|
|
# var type/ecx: (handle tree type-id) = int
|
|
68/push 0/imm32/right/null
|
|
68/push 1/imm32/left/int
|
|
68/push 1/imm32/is-atom
|
|
89/<- %ecx 4/r32/esp
|
|
# var var-var1/ecx: var in eax
|
|
68/push "eax"/imm32/register
|
|
68/push 0/imm32/no-stack-offset
|
|
68/push 1/imm32/block-depth
|
|
51/push-ecx
|
|
68/push "var1"/imm32
|
|
89/<- %ecx 4/r32/esp
|
|
# var type/edx: (handle tree type-id) = literal
|
|
68/push 0/imm32/right/null
|
|
68/push 0/imm32/left/literal
|
|
89/<- %edx 4/r32/esp
|
|
# var var-var2/edx: var literal
|
|
68/push 0/imm32/no-register
|
|
68/push 0/imm32/no-stack-offset
|
|
68/push 1/imm32/block-depth
|
|
52/push-edx
|
|
68/push "0x34"/imm32
|
|
89/<- %edx 4/r32/esp
|
|
# var inouts/esi: (handle stmt-var) = [var2]
|
|
68/push 0/imm32/is-deref:false
|
|
68/push 0/imm32/next
|
|
52/push-edx/var-var2
|
|
89/<- %esi 4/r32/esp
|
|
# inouts = [var1, var2]
|
|
68/push 0/imm32/is-deref:false
|
|
56/push-esi/next
|
|
51/push-ecx/var-var1
|
|
89/<- %esi 4/r32/esp
|
|
# var stmt/esi: statement
|
|
68/push 0/imm32/next
|
|
68/push 0/imm32/no-outputs
|
|
56/push-esi/inouts
|
|
68/push "compare"/imm32/operation
|
|
68/push 1/imm32/regular-stmt
|
|
89/<- %esi 4/r32/esp
|
|
# convert
|
|
c7 0/subop/copy *Curr-block-depth 0/imm32
|
|
(emit-subx-stmt _test-output-buffered-file %esi Primitives)
|
|
(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)
|
|
# var type/ecx: (handle tree type-id) = int
|
|
68/push 0/imm32/right/null
|
|
68/push 1/imm32/left/int
|
|
68/push 1/imm32/is-atom
|
|
89/<- %ecx 4/r32/esp
|
|
# var var-var1/ecx: var in ecx
|
|
68/push "ecx"/imm32/register
|
|
68/push 0/imm32/no-stack-offset
|
|
68/push 1/imm32/block-depth
|
|
51/push-ecx
|
|
68/push "var1"/imm32
|
|
89/<- %ecx 4/r32/esp
|
|
# var type/edx: (handle tree type-id) = literal
|
|
68/push 0/imm32/right/null
|
|
68/push 0/imm32/left/literal
|
|
89/<- %edx 4/r32/esp
|
|
# var var-var2/edx: var literal
|
|
68/push 0/imm32/no-register
|
|
68/push 0/imm32/no-stack-offset
|
|
68/push 1/imm32/block-depth
|
|
52/push-edx
|
|
68/push "0x34"/imm32
|
|
89/<- %edx 4/r32/esp
|
|
# var inouts/esi: (handle stmt-var) = [var2]
|
|
68/push 0/imm32/is-deref:false
|
|
68/push 0/imm32/next
|
|
52/push-edx/var-var2
|
|
89/<- %esi 4/r32/esp
|
|
# inouts = [var1, var2]
|
|
68/push 0/imm32/is-deref:false
|
|
56/push-esi/next
|
|
51/push-ecx/var-var1
|
|
89/<- %esi 4/r32/esp
|
|
# var stmt/esi: statement
|
|
68/push 0/imm32/next
|
|
68/push 0/imm32/no-outputs
|
|
56/push-esi/inouts
|
|
68/push "compare"/imm32/operation
|
|
68/push 1/imm32/regular-stmt
|
|
89/<- %esi 4/r32/esp
|
|
# convert
|
|
c7 0/subop/copy *Curr-block-depth 0/imm32
|
|
(emit-subx-stmt _test-output-buffered-file %esi Primitives)
|
|
(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)
|
|
# var type/ecx: (handle tree type-id) = int
|
|
68/push 0/imm32/right/null
|
|
68/push 1/imm32/left/int
|
|
68/push 1/imm32/is-atom
|
|
89/<- %ecx 4/r32/esp
|
|
# var var-foo/ecx: var
|
|
68/push 0/imm32/no-register
|
|
68/push -8/imm32/stack-offset
|
|
68/push 0/imm32/block-depth
|
|
51/push-ecx
|
|
68/push "foo"/imm32
|
|
89/<- %ecx 4/r32/esp
|
|
# var inouts/esi: (handle stmt-var)
|
|
68/push 0/imm32/is-deref:false
|
|
68/push 0/imm32/next
|
|
51/push-ecx/var-foo
|
|
89/<- %esi 4/r32/esp
|
|
# var stmt/esi: statement
|
|
68/push 0/imm32/next
|
|
68/push 0/imm32/no-outputs
|
|
56/push-esi/inouts
|
|
68/push "f"/imm32/operation
|
|
68/push 1/imm32
|
|
89/<- %esi 4/r32/esp
|
|
# convert
|
|
c7 0/subop/copy *Curr-block-depth 0/imm32
|
|
(emit-subx-stmt _test-output-buffered-file %esi 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 34
|
|
# =>
|
|
# (f2 34)
|
|
#
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
# setup
|
|
(clear-stream _test-output-stream)
|
|
(clear-stream $_test-output-buffered-file->buffer)
|
|
# var type/ecx: (handle tree type-id) = literal
|
|
68/push 0/imm32/right/null
|
|
68/push 0/imm32/left/literal
|
|
89/<- %ecx 4/r32/esp
|
|
# var var-foo/ecx: var literal
|
|
68/push 0/imm32/no-register
|
|
68/push 0/imm32/no-stack-offset
|
|
68/push 0/imm32/block-depth
|
|
51/push-ecx
|
|
68/push "34"/imm32
|
|
89/<- %ecx 4/r32/esp
|
|
# var inouts/esi: (handle stmt-var)
|
|
68/push 0/imm32/is-deref:false
|
|
68/push 0/imm32/next
|
|
51/push-ecx/var-foo
|
|
89/<- %esi 4/r32/esp
|
|
# var stmt/esi: statement
|
|
68/push 0/imm32/next
|
|
68/push 0/imm32/no-outputs
|
|
56/push-esi/inouts
|
|
68/push "f"/imm32/operation
|
|
68/push 1/imm32
|
|
89/<- %esi 4/r32/esp
|
|
# convert
|
|
c7 0/subop/copy *Curr-block-depth 0/imm32
|
|
(emit-subx-stmt _test-output-buffered-file %esi 0 %ebx)
|
|
(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 34)" "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
|