mu/apps/mu.subx

15230 lines
612 KiB
Plaintext
Raw Normal View History

2019-11-03 07:43:37 +00:00
# The Mu computer's level-2 language, also called Mu.
# http://akkartik.name/post/mu-2019-2
#
# To run:
2020-01-27 10:12:37 +00:00
# $ ./translate_subx init.linux [0-9]*.subx apps/mu.subx
2019-11-08 19:32:14 +00:00
# == 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.
2019-11-08 19:32:14 +00:00
# - minimize impedance mismatch between source language and SubX target
2019-12-07 19:21:30 +00:00
# (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)
2019-11-08 19:32:14 +00:00
# == Language description
2020-04-25 02:51:16 +00:00
# A program is a sequence of function and type definitions.
2019-11-08 19:32:14 +00:00
#
# 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.
2019-11-08 19:32:14 +00:00
# eax ecx edx ebx esi edi
# Variables in registers must be primitive 32-bit types.
2019-11-08 19:32:14 +00:00
# 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.
#
2019-11-08 19:32:14 +00:00
# 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.
2019-11-08 19:32:14 +00:00
#
# Statement outputs, like function outputs, must be variables in registers.
2019-11-08 19:32:14 +00:00
#
# 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)
2019-11-08 19:32:14 +00:00
# There's no initializer; variables are automatically initialized.
# The type of a local variable is either word-length (4 bytes) or starts with 'ref'.
2019-11-08 19:32:14 +00:00
#
# - variables definitions in a register. E.g.:
2020-01-27 08:36:44 +00:00
# - var foo/eax: int <- add bar 1
2019-11-08 19:32:14 +00:00
# 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.
2020-01-27 08:36:44 +00:00
# - var eax: int <- foo bar quux
# var floo/ecx: int <- copy eax
2019-11-08 19:32:14 +00:00
#
# 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
2019-11-09 17:34:57 +00:00
#
# 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.
#
2019-11-09 17:34:57 +00:00
# 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)
2019-11-09 17:34:57 +00:00
# A var-type contains:
# name: (handle array byte)
2020-01-09 08:06:38 +00:00
# type: (handle tree type-id)
2019-11-26 05:00:07 +00:00
#
# A statement can be:
# tag 0: a block
# tag 1: a simple statement (stmt1)
2019-11-26 05:00:07 +00:00
# tag 2: a variable defined on the stack
# tag 3: a variable defined in a register
#
# A block contains:
# tag: 0
2020-02-21 23:36:18 +00:00
# statements: (handle list stmt)
2020-02-07 00:29:40 +00:00
# name: (handle array byte) -- starting with '$'
2019-11-26 05:00:07 +00:00
#
# A regular statement contains:
# tag: 1
# operation: (handle array byte)
# inouts: (handle list operand)
# outputs: (handle list var)
2019-11-26 05:00:07 +00:00
#
# A variable defined on the stack contains:
# tag: 2
# name: (handle array byte)
2020-01-09 08:06:38 +00:00
# type: (handle tree type-id)
2019-11-26 05:00:07 +00:00
#
# A variable defined in a register contains:
# tag: 3
# name: (handle array byte)
2020-01-09 08:06:38 +00:00
# type: (handle tree type-id)
# reg: (handle array byte)
2019-11-09 17:34:57 +00:00
# == Translation: managing the stack
2019-11-08 19:32:14 +00:00
# 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
#
2019-11-09 17:34:57 +00:00
# Formal types:
# live-vars: stack of vars
# var:
# name: (handle array byte)
2020-01-09 08:06:38 +00:00
# type: (handle tree type-id)
2019-11-09 17:34:57 +00:00
# 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.
2019-11-08 19:32:14 +00:00
# == 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)
2019-11-08 19:32:14 +00:00
# == 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
2019-11-09 01:31:11 +00:00
# == Translating a block
2019-11-09 01:31:11 +00:00
# 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
2020-02-23 08:35:02 +00:00
Program:
_Program-functions: # (handle function)
0/imm32
_Program-functions->payload:
0/imm32
2020-02-23 08:35:02 +00:00
_Program-types: # (handle typeinfo)
0/imm32
_Program-types->payload:
0/imm32
2020-02-23 22:36:18 +00:00
# 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)
2019-11-09 20:09:20 +00:00
0/imm32
Function-inouts: # (handle list var)
8/imm32
Function-outputs: # (handle list var)
2019-11-09 20:09:20 +00:00
0x10/imm32
Function-body: # (handle block)
0x18/imm32
Function-next: # (handle function)
0x20/imm32
2020-01-20 04:43:24 +00:00
Function-size: # (addr int)
2020-05-15 07:18:37 +00:00
0x28/imm32/40
2019-11-09 20:09:20 +00:00
2020-02-23 22:36:18 +00:00
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
2020-01-20 04:43:24 +00:00
Primitive-size: # (addr int)
2020-05-15 07:18:37 +00:00
0x3c/imm32/60
2020-02-23 22:36:18 +00:00
Stmt-tag: # int
2019-11-26 05:00:07 +00:00
0/imm32
2020-02-21 23:36:18 +00:00
Block-stmts: # (handle list stmt)
2019-11-26 05:00:07 +00:00
4/imm32
Block-var: # (handle var)
0xc/imm32
2019-11-26 05:00:07 +00:00
Stmt1-operation: # (handle array byte)
2019-11-26 05:00:07 +00:00
4/imm32
Stmt1-inouts: # (handle stmt-var)
2019-11-26 05:00:07 +00:00
0xc/imm32
Stmt1-outputs: # (handle stmt-var)
0x14/imm32
2019-11-26 05:00:07 +00:00
2020-01-26 22:02:54 +00:00
Vardef-var: # (handle var)
2019-11-26 05:00:07 +00:00
4/imm32
2020-01-26 22:02:54 +00:00
Regvardef-operation: # (handle array byte)
2019-11-26 05:00:07 +00:00
4/imm32
Regvardef-inouts: # (handle stmt-var)
2019-11-26 05:00:07 +00:00
0xc/imm32
Regvardef-outputs: # (handle stmt-var) # will have exactly one element
0x14/imm32
2019-11-26 05:00:07 +00:00
2020-01-20 04:43:24 +00:00
Stmt-size: # (addr int)
0x1c/imm32
2020-02-23 22:36:18 +00:00
Var-name: # (handle array byte)
2019-11-09 20:09:20 +00:00
0/imm32
2020-02-23 22:36:18 +00:00
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
2020-02-23 22:36:18 +00:00
Var-register: # (handle array byte) -- name of a register
0x18/imm32
2020-01-20 04:43:24 +00:00
Var-size: # (addr int)
0x20/imm32
2019-11-09 20:09:20 +00:00
List-value: # (handle _)
0/imm32
2020-02-23 22:36:18 +00:00
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
2020-01-09 08:06:38 +00:00
# Types are expressed as trees (s-expressions) of type-ids (ints).
2020-01-10 18:35:48 +00:00
# However, there's no need for singletons, so we can assume (int) == int
2020-01-09 08:06:38 +00:00
# - if x->right == nil, x is an atom
# - x->left contains either a pointer to a pair, or an atomic type-id directly.
2020-04-12 09:33:01 +00:00
Tree-is-atom: # boolean
2020-01-09 08:06:38 +00:00
0/imm32
2020-04-12 09:33:01 +00:00
# if left-is-atom?
Tree-value: # type-id
2020-01-09 08:06:38 +00:00
4/imm32
2020-04-12 09:33:01 +00:00
# unless left-is-atom?
Tree-left: # (addr tree type-id)
4/imm32
Tree-right: # (addr tree type-id)
0xc/imm32
2020-04-12 09:33:01 +00:00
#
Tree-size: # (addr int)
0x14/imm32
2020-01-09 08:06:38 +00:00
2020-02-23 08:30:31 +00:00
# Types
# TODO: heap allocations here can't be reclaimed
2020-04-24 01:56:08 +00:00
Type-id: # (stream (addr array byte))
0x1c/imm32/write
2020-02-23 08:30:31 +00:00
0/imm32/read
0x100/imm32/size
2020-02-23 08:30:31 +00:00
# data
"literal"/imm32 # 0: value is just the name
2020-02-23 08:30:31 +00:00
"int"/imm32 # 1
"addr"/imm32 # 2
"array"/imm32 # 3
"handle"/imm32 # 4
2020-02-23 22:42:22 +00:00
"boolean"/imm32 # 5
"constant"/imm32 # 6: like a literal, but value is an int in Var-offset
"offset"/imm32 # 7: (offset T) is guaranteed to be a 32-bit multiple of size-of(T)
2020-02-23 08:30:31 +00:00
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
2020-04-25 02:51:16 +00:00
# == Type definitions
# Program->types contains some typeinfo for each type definition.
2020-02-23 08:30:31 +00:00
# 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))
2020-02-23 08:30:31 +00:00
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.
2020-02-28 02:49:50 +00:00
Typeinfo-total-size-in-bytes: # int
2020-02-23 08:30:31 +00:00
0xc/imm32
Typeinfo-next: # (handle typeinfo)
2020-02-28 02:49:50 +00:00
0x10/imm32
Typeinfo-size: # (addr int)
0x18/imm32
2020-02-23 08:30:31 +00:00
# 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
2019-11-03 07:43:37 +00:00
# if (argv[1] != "test") break
(kernel-string-equal? *(ebp+8) "test") # => eax
2020-02-17 23:26:49 +00:00
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
2020-01-27 08:36:44 +00:00
convert-mu: # in: (addr buffered-file), out: (addr buffered-file)
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
2020-03-08 08:35:48 +00:00
# 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
2020-03-08 08:35:48 +00:00
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)
2020-05-24 07:51:52 +00:00
#? (dump-typeinfos "=== typeinfos\n")
(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
2019-11-08 19:32:14 +00:00
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)
2019-11-08 19:32:14 +00:00
(clear-stream _test-output-stream)
(clear-stream $_test-output-buffered-file->buffer)
2019-11-08 19:32:14 +00:00
#
(write _test-input-stream "fn foo n: int {\n")
2019-11-08 19:32:14 +00:00
(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")
2019-11-08 19:32:14 +00:00
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
2019-12-23 07:42:14 +00:00
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")
2019-12-23 07:42:14 +00:00
# . 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)
#
2019-12-28 07:59:07 +00:00
(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
2020-03-12 07:36:36 +00:00
test-convert-function-with-literal-arg:
2020-01-01 05:58:52 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(clear-stream _test-input-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
2020-03-12 07:36:36 +00:00
(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")
2020-03-12 07:36:36 +00:00
(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")
2020-01-01 05:58:52 +00:00
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
2020-03-12 07:36:36 +00:00
test-convert-function-with-literal-arg-2:
2020-01-01 05:58:52 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(clear-stream _test-input-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
2020-03-12 07:36:36 +00:00
(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")
2020-03-12 07:36:36 +00:00
(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")
2020-01-01 05:58:52 +00:00
# . 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
2020-05-18 07:54:53 +00:00
test-convert-function-with-local-var-in-mem:
2020-01-27 10:07:00 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(clear-stream _test-input-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")
2020-01-27 10:07:00 +00:00
(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")
2020-01-27 10:07:00 +00:00
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
2020-05-18 08:02:35 +00:00
test-convert-function-with-local-var-with-compound-type-in-mem:
2020-03-11 02:30:03 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(clear-stream _test-input-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
2020-05-18 08:02:35 +00:00
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
2020-05-19 06:26:40 +00:00
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
2020-05-19 06:26:40 +00:00
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
2020-05-19 06:26:40 +00:00
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")
2020-01-30 01:34:07 +00:00
(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:
6082 - bugfix in spilling register vars In the process I'm starting to realize that my approach to avoiding spills isn't ideal. It works for local variables but not to avoid spilling outputs. To correctly decide whether to spill to an output register or not, we really need to analyze when a variable is live. If we don't do that, we'll end up in one of two bad situations: a) Don't spill the outermost use of an output register (or just the outermost scope in a function). This is weird because it's hard to explain to the programmer why they can overwrite a local with an output above a '{' but not below. b) Disallow overwriting entirely. This is easier to communicate but quite inconvenient. It's nice to be able to use eax for some temporary purpose before overwriting it with the final result of a function. If we instead track liveness, things are convenient and also easier to explain. If a temporary is used after the output has been written that's an obvious problem: "you clobbered the output". (It seems more reasonable to disallow multiple live ranges for the output. Once an output is written it can only be shadowed in a nested block.) That's the bad news. Now for some good news: One lovely property Mu the language has at the moment is that live ranges are guaranteed to be linear segments of code. We don't need to analyze loop-carried dependences. This means that we can decide whether a variable is live purely by scanning later statements for its use. (Defining 'register use' is slightly non-trivial; primitives must somehow specify when they read their output register.) So we don't actually need to worry about a loop reading a register with one type and writing to another type at the end of an iteration. The only way that can happen is if the write at the end was to a local variable, and we're guaranteeing that local variables will be reclaimed at the end of the iteration. So, the sequence of tasks: a) compute register liveness b1) verify that all register variables used at any point in a program are always the topmost use of that register. b2) decide whether to spill/shadow, clobber or flag an error. There's still the open question of where to attach liveness state. It can't be on a var, because liveness varies by use of the var. It can't be on a statement because we may want to know the liveness of variables not referenced in a given statement. Conceptually we want a matrix of locals x stmts (flattened). But I think it's simpler than that. We just want to know liveness at the time of variable declarations. A new register variable can be in one of three states w.r.t. its previous definition: either it's shadowing it, or it can clobber it, or there's a conflict and we need to raise an error. I think we can compute this information for each variable definition by an analysis similar to existing ones, maintaining a stack of variable definitions. The major difference is that we don't pop variables when a block ends. Details to be worked out. But when we do I hope to get these pending tests passing.
2020-03-06 08:06:42 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(clear-stream _test-input-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:
6082 - bugfix in spilling register vars In the process I'm starting to realize that my approach to avoiding spills isn't ideal. It works for local variables but not to avoid spilling outputs. To correctly decide whether to spill to an output register or not, we really need to analyze when a variable is live. If we don't do that, we'll end up in one of two bad situations: a) Don't spill the outermost use of an output register (or just the outermost scope in a function). This is weird because it's hard to explain to the programmer why they can overwrite a local with an output above a '{' but not below. b) Disallow overwriting entirely. This is easier to communicate but quite inconvenient. It's nice to be able to use eax for some temporary purpose before overwriting it with the final result of a function. If we instead track liveness, things are convenient and also easier to explain. If a temporary is used after the output has been written that's an obvious problem: "you clobbered the output". (It seems more reasonable to disallow multiple live ranges for the output. Once an output is written it can only be shadowed in a nested block.) That's the bad news. Now for some good news: One lovely property Mu the language has at the moment is that live ranges are guaranteed to be linear segments of code. We don't need to analyze loop-carried dependences. This means that we can decide whether a variable is live purely by scanning later statements for its use. (Defining 'register use' is slightly non-trivial; primitives must somehow specify when they read their output register.) So we don't actually need to worry about a loop reading a register with one type and writing to another type at the end of an iteration. The only way that can happen is if the write at the end was to a local variable, and we're guaranteeing that local variables will be reclaimed at the end of the iteration. So, the sequence of tasks: a) compute register liveness b1) verify that all register variables used at any point in a program are always the topmost use of that register. b2) decide whether to spill/shadow, clobber or flag an error. There's still the open question of where to attach liveness state. It can't be on a var, because liveness varies by use of the var. It can't be on a statement because we may want to know the liveness of variables not referenced in a given statement. Conceptually we want a matrix of locals x stmts (flattened). But I think it's simpler than that. We just want to know liveness at the time of variable declarations. A new register variable can be in one of three states w.r.t. its previous definition: either it's shadowing it, or it can clobber it, or there's a conflict and we need to raise an error. I think we can compute this information for each variable definition by an analysis similar to existing ones, maintaining a stack of variable definitions. The major difference is that we don't pop variables when a block ends. Details to be worked out. But when we do I hope to get these pending tests passing.
2020-03-06 08:06:42 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(clear-stream _test-input-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
2020-05-21 06:48:38 +00:00
test-do-not-spill-same-register-in-block:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(clear-stream _test-input-stream)
(clear-stream $_test-input-buffered-file->buffer)
(clear-stream _test-output-stream)
(clear-stream $_test-output-buffered-file->buffer)
#
(write _test-input-stream "fn foo {\n")
(write _test-input-stream " var x/ecx: int <- copy 3\n")
(write _test-input-stream " var y/ecx: int <- copy 4\n")
(write _test-input-stream " y <- increment\n")
(write _test-input-stream "}\n")
# convert
(convert-mu _test-input-buffered-file _test-output-buffered-file)
(flush _test-output-buffered-file)
#? # dump _test-output-stream {{{
#? (write 2 "^")
#? (write-stream 2 _test-output-stream)
#? (write 2 "$\n")
#? (rewind-stream _test-output-stream)
#? # }}}
# check output
(check-next-stream-line-equal _test-output-stream "foo:" "F - test-do-not-spill-same-register-in-block/0")
(check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-do-not-spill-same-register-in-block/1")
(check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-do-not-spill-same-register-in-block/2")
(check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-do-not-spill-same-register-in-block/3")
(check-next-stream-line-equal _test-output-stream " {" "F - test-do-not-spill-same-register-in-block/4")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-do-not-spill-same-register-in-block/5")
(check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-do-not-spill-same-register-in-block/6")
(check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-do-not-spill-same-register-in-block/7")
(check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 4/imm32" "F - test-do-not-spill-same-register-in-block/8")
(check-next-stream-line-equal _test-output-stream " 41/increment-ecx" "F - test-do-not-spill-same-register-in-block/9")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-do-not-spill-same-register-in-block/10")
(check-next-stream-line-equal _test-output-stream " }" "F - test-do-not-spill-same-register-in-block/11")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-do-not-spill-same-register-in-block/12")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-do-not-spill-same-register-in-block/13")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-do-not-spill-same-register-in-block/14")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-do-not-spill-same-register-in-block/15")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-do-not-spill-same-register-in-block/16")
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
test-spill-different-register-in-block:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(clear-stream _test-input-stream)
(clear-stream $_test-input-buffered-file->buffer)
(clear-stream _test-output-stream)
(clear-stream $_test-output-buffered-file->buffer)
#
(write _test-input-stream "fn foo {\n")
(write _test-input-stream " var x/eax: int <- copy 3\n")
(write _test-input-stream " var y/ecx: int <- copy 4\n")
(write _test-input-stream " y <- increment\n")
(write _test-input-stream "}\n")
# convert
(convert-mu _test-input-buffered-file _test-output-buffered-file)
(flush _test-output-buffered-file)
#? # dump _test-output-stream {{{
#? (write 2 "^")
#? (write-stream 2 _test-output-stream)
#? (write 2 "$\n")
#? (rewind-stream _test-output-stream)
#? # }}}
# check output
(check-next-stream-line-equal _test-output-stream "foo:" "F - test-spill-different-register-in-block/0")
(check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-spill-different-register-in-block/1")
(check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-spill-different-register-in-block/2")
(check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-spill-different-register-in-block/3")
(check-next-stream-line-equal _test-output-stream " {" "F - test-spill-different-register-in-block/4")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-spill-different-register-in-block/5")
(check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-spill-different-register-in-block/6")
(check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 3/imm32" "F - test-spill-different-register-in-block/7")
(check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-spill-different-register-in-block/8")
(check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 4/imm32" "F - test-spill-different-register-in-block/9")
(check-next-stream-line-equal _test-output-stream " 41/increment-ecx" "F - test-spill-different-register-in-block/10")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-spill-different-register-in-block/11")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-spill-different-register-in-block/12")
(check-next-stream-line-equal _test-output-stream " }" "F - test-spill-different-register-in-block/13")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-spill-different-register-in-block/14")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-spill-different-register-in-block/15")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-spill-different-register-in-block/16")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-spill-different-register-in-block/17")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-spill-different-register-in-block/18")
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
test-shadow-live-output:
6082 - bugfix in spilling register vars In the process I'm starting to realize that my approach to avoiding spills isn't ideal. It works for local variables but not to avoid spilling outputs. To correctly decide whether to spill to an output register or not, we really need to analyze when a variable is live. If we don't do that, we'll end up in one of two bad situations: a) Don't spill the outermost use of an output register (or just the outermost scope in a function). This is weird because it's hard to explain to the programmer why they can overwrite a local with an output above a '{' but not below. b) Disallow overwriting entirely. This is easier to communicate but quite inconvenient. It's nice to be able to use eax for some temporary purpose before overwriting it with the final result of a function. If we instead track liveness, things are convenient and also easier to explain. If a temporary is used after the output has been written that's an obvious problem: "you clobbered the output". (It seems more reasonable to disallow multiple live ranges for the output. Once an output is written it can only be shadowed in a nested block.) That's the bad news. Now for some good news: One lovely property Mu the language has at the moment is that live ranges are guaranteed to be linear segments of code. We don't need to analyze loop-carried dependences. This means that we can decide whether a variable is live purely by scanning later statements for its use. (Defining 'register use' is slightly non-trivial; primitives must somehow specify when they read their output register.) So we don't actually need to worry about a loop reading a register with one type and writing to another type at the end of an iteration. The only way that can happen is if the write at the end was to a local variable, and we're guaranteeing that local variables will be reclaimed at the end of the iteration. So, the sequence of tasks: a) compute register liveness b1) verify that all register variables used at any point in a program are always the topmost use of that register. b2) decide whether to spill/shadow, clobber or flag an error. There's still the open question of where to attach liveness state. It can't be on a var, because liveness varies by use of the var. It can't be on a statement because we may want to know the liveness of variables not referenced in a given statement. Conceptually we want a matrix of locals x stmts (flattened). But I think it's simpler than that. We just want to know liveness at the time of variable declarations. A new register variable can be in one of three states w.r.t. its previous definition: either it's shadowing it, or it can clobber it, or there's a conflict and we need to raise an error. I think we can compute this information for each variable definition by an analysis similar to existing ones, maintaining a stack of variable definitions. The major difference is that we don't pop variables when a block ends. Details to be worked out. But when we do I hope to get these pending tests passing.
2020-03-06 08:06:42 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(clear-stream _test-input-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")
6082 - bugfix in spilling register vars In the process I'm starting to realize that my approach to avoiding spills isn't ideal. It works for local variables but not to avoid spilling outputs. To correctly decide whether to spill to an output register or not, we really need to analyze when a variable is live. If we don't do that, we'll end up in one of two bad situations: a) Don't spill the outermost use of an output register (or just the outermost scope in a function). This is weird because it's hard to explain to the programmer why they can overwrite a local with an output above a '{' but not below. b) Disallow overwriting entirely. This is easier to communicate but quite inconvenient. It's nice to be able to use eax for some temporary purpose before overwriting it with the final result of a function. If we instead track liveness, things are convenient and also easier to explain. If a temporary is used after the output has been written that's an obvious problem: "you clobbered the output". (It seems more reasonable to disallow multiple live ranges for the output. Once an output is written it can only be shadowed in a nested block.) That's the bad news. Now for some good news: One lovely property Mu the language has at the moment is that live ranges are guaranteed to be linear segments of code. We don't need to analyze loop-carried dependences. This means that we can decide whether a variable is live purely by scanning later statements for its use. (Defining 'register use' is slightly non-trivial; primitives must somehow specify when they read their output register.) So we don't actually need to worry about a loop reading a register with one type and writing to another type at the end of an iteration. The only way that can happen is if the write at the end was to a local variable, and we're guaranteeing that local variables will be reclaimed at the end of the iteration. So, the sequence of tasks: a) compute register liveness b1) verify that all register variables used at any point in a program are always the topmost use of that register. b2) decide whether to spill/shadow, clobber or flag an error. There's still the open question of where to attach liveness state. It can't be on a var, because liveness varies by use of the var. It can't be on a statement because we may want to know the liveness of variables not referenced in a given statement. Conceptually we want a matrix of locals x stmts (flattened). But I think it's simpler than that. We just want to know liveness at the time of variable declarations. A new register variable can be in one of three states w.r.t. its previous definition: either it's shadowing it, or it can clobber it, or there's a conflict and we need to raise an error. I think we can compute this information for each variable definition by an analysis similar to existing ones, maintaining a stack of variable definitions. The major difference is that we don't pop variables when a block ends. Details to be worked out. But when we do I hope to get these pending tests passing.
2020-03-06 08:06:42 +00:00
(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:
2020-01-29 07:44:04 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(clear-stream _test-input-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")
2020-01-29 07:44:04 +00:00
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
2020-05-20 19:35:39 +00:00
test-convert-function-with-branches-in-named-block:
2020-01-30 01:34:07 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(clear-stream _test-input-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")
2020-01-30 01:34:07 +00:00
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
2020-05-20 19:35:39 +00:00
test-convert-function-with-var-in-nested-block:
2020-02-02 01:05:59 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(clear-stream _test-input-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")
2020-02-02 01:05:59 +00:00
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
test-convert-function-with-multiple-vars-in-nested-blocks:
2020-02-02 01:05:59 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(clear-stream _test-input-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")
2020-02-02 01:05:59 +00:00
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
2020-05-21 05:33:43 +00:00
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
2020-05-21 05:57:42 +00:00
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
2020-05-21 05:57:42 +00:00
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
2020-05-21 05:57:42 +00:00
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
2020-05-21 06:27:45 +00:00
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
2020-05-21 06:27:45 +00:00
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
2020-05-21 06:27:45 +00:00
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
2020-05-21 06:27:45 +00:00
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:
2020-03-12 02:55:45 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(clear-stream _test-input-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
2020-05-21 07:01:50 +00:00
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")
2020-05-24 20:27:08 +00:00
(check-next-stream-line-equal _test-output-stream " 8b/-> *eax 0x00000000/r32" "F - test-convert-length-of-array/8")
(check-next-stream-line-equal _test-output-stream " c1/shift 5/subop/>> %eax 0x00000002/imm32" "F - test-convert-length-of-array/9")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-length-of-array/10")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-length-of-array/11")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-length-of-array/12")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-length-of-array/13")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-length-of-array/14")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-length-of-array/15")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-length-of-array/16")
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
2020-05-21 07:01:50 +00:00
test-convert-length-of-array-on-stack:
2020-03-12 07:45:17 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(clear-stream _test-input-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")
2020-05-24 20:27:08 +00:00
(check-next-stream-line-equal _test-output-stream " c1/shift 5/subop/>> %eax 0x00000002/imm32" "F - test-convert-length-of-array-on-stack/10")
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-length-of-array-on-stack/11")
(check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000010/imm32" "F - test-convert-length-of-array-on-stack/12")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-length-of-array-on-stack/13")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-length-of-array-on-stack/14")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-length-of-array-on-stack/15")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-length-of-array-on-stack/16")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-length-of-array-on-stack/17")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-length-of-array-on-stack/18")
2020-03-12 07:45:17 +00:00
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
2020-05-21 07:23:55 +00:00
test-convert-index-into-array:
2020-02-21 23:19:34 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(clear-stream _test-input-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
2020-02-29 13:33:03 +00:00
(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")
2020-02-29 13:33:03 +00:00
(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")
2020-02-21 23:19:34 +00:00
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
2020-05-21 07:23:55 +00:00
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
2020-05-21 22:36:31 +00:00
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
2020-05-21 22:36:31 +00:00
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:
2020-03-08 02:59:57 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(clear-stream _test-input-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")
2020-03-08 02:59:57 +00:00
(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
2020-05-22 21:43:26 +00:00
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
2020-02-28 01:31:35 +00:00
(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")
2020-02-28 01:31:35 +00:00
(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
2020-05-22 22:56:38 +00:00
test-convert-function-with-local-var-with-user-defined-type:
2020-02-28 02:49:50 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(clear-stream _test-input-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
2020-05-22 22:56:38 +00:00
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
2020-03-14 23:04:57 +00:00
# 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:
2020-03-14 23:04:57 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(clear-stream _test-input-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")
2020-03-14 23:04:57 +00:00
(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
2020-05-23 19:53:20 +00:00
test-convert-get-on-local-variable:
2020-03-10 23:39:06 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(clear-stream _test-input-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
2020-05-23 19:53:20 +00:00
(check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-get-on-local-variable/0")
(check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-get-on-local-variable/1")
(check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-get-on-local-variable/2")
(check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-get-on-local-variable/3")
(check-next-stream-line-equal _test-output-stream " {" "F - test-convert-get-on-local-variable/4")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-get-on-local-variable/5")
2020-03-10 23:39:06 +00:00
# var a
2020-05-23 19:53:20 +00:00
(check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-get-on-local-variable/6")
(check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-get-on-local-variable/7")
2020-03-10 23:39:06 +00:00
# var c
2020-05-23 19:53:20 +00:00
(check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-get-on-local-variable/8")
2020-03-10 23:39:06 +00:00
# get
2020-05-23 19:53:20 +00:00
(check-next-stream-line-equal _test-output-stream " 8d/copy-address *(ebp+0xfffffffc) 0x00000001/r32" "F - test-convert-get-on-local-variable/9")
2020-03-10 23:39:06 +00:00
# reclaim c
2020-05-23 19:53:20 +00:00
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-get-on-local-variable/10")
2020-03-10 23:39:06 +00:00
# reclaim a
2020-05-23 19:53:20 +00:00
(check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000008/imm32" "F - test-convert-get-on-local-variable/11")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-get-on-local-variable/12")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-get-on-local-variable/13")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-get-on-local-variable/14")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-get-on-local-variable/15")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-get-on-local-variable/16")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-get-on-local-variable/17")
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
test-convert-get-on-function-argument:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(clear-stream _test-input-stream)
(clear-stream $_test-input-buffered-file->buffer)
(clear-stream _test-output-stream)
(clear-stream $_test-output-buffered-file->buffer)
#
(write _test-input-stream "fn foo a: t {\n")
(write _test-input-stream " var c/ecx: (addr int) <- get a, y\n")
(write _test-input-stream "}\n")
(write _test-input-stream "type t {\n")
(write _test-input-stream " x: int\n")
(write _test-input-stream " y: int\n")
(write _test-input-stream "}\n")
# convert
(convert-mu _test-input-buffered-file _test-output-buffered-file)
(flush _test-output-buffered-file)
#? # dump _test-output-stream {{{
#? (write 2 "^")
#? (write-stream 2 _test-output-stream)
#? (write 2 "$\n")
#? (rewind-stream _test-output-stream)
#? # }}}
# check output
(check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-get-on-function-argument/0")
(check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-get-on-function-argument/1")
(check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-get-on-function-argument/2")
(check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-get-on-function-argument/3")
(check-next-stream-line-equal _test-output-stream " {" "F - test-convert-get-on-function-argument/4")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-get-on-function-argument/5")
# var c
(check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-get-on-function-argument/6")
# get
(check-next-stream-line-equal _test-output-stream " 8d/copy-address *(ebp+0x0000000c) 0x00000001/r32" "F - test-convert-get-on-function-argument/7")
# reclaim c
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument/8")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-get-on-function-argument/9")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-get-on-function-argument/10")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-get-on-function-argument/11")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-get-on-function-argument/12")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-get-on-function-argument/13")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-get-on-function-argument/14")
2020-03-10 23:39:06 +00:00
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
2020-05-24 07:51:52 +00:00
test-convert-get-on-function-argument-with-known-type:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(clear-stream _test-input-stream)
(clear-stream $_test-input-buffered-file->buffer)
(clear-stream _test-output-stream)
(clear-stream $_test-output-buffered-file->buffer)
#
(write _test-input-stream "type t {\n")
(write _test-input-stream " x: int\n")
(write _test-input-stream " y: int\n")
(write _test-input-stream "}\n")
(write _test-input-stream "fn foo a: t {\n")
(write _test-input-stream " var c/ecx: (addr int) <- get a, y\n")
(write _test-input-stream "}\n")
# convert
(convert-mu _test-input-buffered-file _test-output-buffered-file)
(flush _test-output-buffered-file)
#? # dump _test-output-stream {{{
#? (write 2 "^")
#? (write-stream 2 _test-output-stream)
#? (write 2 "$\n")
#? (rewind-stream _test-output-stream)
#? # }}}
# check output
(check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-get-on-function-argument-with-known-type/0")
(check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-get-on-function-argument-with-known-type/1")
(check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-get-on-function-argument-with-known-type/2")
(check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-get-on-function-argument-with-known-type/3")
(check-next-stream-line-equal _test-output-stream " {" "F - test-convert-get-on-function-argument-with-known-type/4")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-get-on-function-argument-with-known-type/5")
# var c
(check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-get-on-function-argument-with-known-type/6")
# get
(check-next-stream-line-equal _test-output-stream " 8d/copy-address *(ebp+0x0000000c) 0x00000001/r32" "F - test-convert-get-on-function-argument-with-known-type/7")
# reclaim c
(check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument-with-known-type/8")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-get-on-function-argument-with-known-type/9")
(check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-get-on-function-argument-with-known-type/10")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-get-on-function-argument-with-known-type/11")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-get-on-function-argument-with-known-type/12")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-get-on-function-argument-with-known-type/13")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-get-on-function-argument-with-known-type/14")
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
test-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
2019-11-28 00:50:23 +00:00
#######################################################
# Parsing
#######################################################
2020-01-27 08:36:44 +00:00
parse-mu: # in: (addr buffered-file)
# pseudocode
2020-04-23 05:35:06 +00:00
# var curr-function: (addr handle function) = Program->functions
# var curr-type: (addr handle typeinfo) = Program->types
2020-01-27 08:36:44 +00:00
# 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
2020-01-27 22:14:40 +00:00
# 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
2020-02-23 08:35:02 +00:00
# else if slice-equal?(word-slice, "fn")
2020-01-27 08:36:44 +00:00
# var new-function: (handle function) = allocate(function)
2020-04-24 00:31:28 +00:00
# var vars: (stack (handle var) 256)
2020-04-23 05:35:06 +00:00
# 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
2020-02-23 08:35:02 +00:00
56/push-esi
57/push-edi
2020-01-27 08:36:44 +00:00
# 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
2020-01-27 08:36:44 +00:00
# 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)
2020-02-23 08:35:02 +00:00
bf/copy-to-edi _Program-functions/imm32
2020-04-24 00:31:28 +00:00
# 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)
#? # }}}
2020-01-27 22:14:40 +00:00
(next-mu-token %ecx %edx)
# if slice-empty?(word-slice) continue
2020-04-23 02:01:17 +00:00
(slice-empty? %edx) # => eax
2020-02-17 23:26:49 +00:00
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:
2020-04-23 02:01:17 +00:00
(slice-equal? %edx "fn") # => eax
2020-02-17 23:26:49 +00:00
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)
2020-04-23 02:01:17 +00:00
# var new-function-addr/eax: (addr function)
(lookup *esi *(esi+4)) # => eax
(clear-stack %ebx)
2020-04-23 02:01:17 +00:00
(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
2020-05-18 01:11:13 +00:00
8d/copy-address *(eax+0x20) 7/r32/edi # Function-next
# reclaim new-function
81 0/subop/add %esp 8/imm32
#
e9/jump $parse-mu:line-loop/disp32
}
# if (slice-equal?(word-slice, "type")) parse a type (struct/record) definition
{
$parse-mu:type:
2020-04-23 02:01:17 +00:00
(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
2020-04-24 00:24:17 +00:00
# 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 '{'
2020-05-22 21:43:26 +00:00
#? (dump-typeinfos "=== aaa\n")
(populate-mu-type *(ebp+8) %eax) # => eax
2020-05-22 21:43:26 +00:00
#? (dump-typeinfos "=== zzz\n")
2020-04-24 00:24:17 +00:00
# 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
2020-02-23 08:35:02 +00:00
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 {
2020-01-27 08:36:44 +00:00
# ✗ fn foo x: {
# ✓ fn foo x: int {
# ✓ fn foo x: int {
# ✓ fn foo x: int -> y/eax: int {
2020-04-23 02:01:17 +00:00
populate-mu-function-header: # first-line: (addr stream byte), out: (addr function), vars: (addr stack (handle var))
# pseudocode:
2020-01-27 08:36:44 +00:00
# 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 != '}')
2020-01-27 08:36:44 +00:00
# var v: (handle var) = parse-var-with-type(name, first-line)
# assert(v->register == null)
2020-02-02 01:05:59 +00:00
# # 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 '{' '}' '->')
2020-01-27 08:36:44 +00:00
# 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
2020-01-27 08:36:44 +00:00
# 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)
2019-11-28 03:11:16 +00:00
# error checking
2020-02-07 08:01:59 +00:00
# TODO: error if name starts with 'break' or 'loop'
2019-11-28 03:11:16 +00:00
# if (word-slice == '{') abort
(slice-equal? %ecx "{") # => eax
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
2019-11-28 03:11:16 +00:00
# if (word-slice == '->') abort
(slice-equal? %ecx "->") # => eax
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
2019-11-28 03:11:16 +00:00
# if (word-slice == '}') abort
(slice-equal? %ecx "}") # => eax
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
# save function name
2020-05-09 23:27:20 +00:00
(slice-to-string Heap %ecx %edi) # Function-name
2019-11-28 03:11:16 +00:00
# save function inouts
{
$populate-mu-function-header:check-for-inout:
(next-mu-token *(ebp+8) %ecx)
# if (word-slice == '{') goto done
2019-11-28 03:11:16 +00:00
(slice-equal? %ecx "{") # => eax
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
0f 85/jump-if-!= $populate-mu-function-header:done/disp32
2019-11-28 03:11:16 +00:00
# if (word-slice == '->') break
(slice-equal? %ecx "->") # => eax
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
0f 85/jump-if-!= break/disp32
2019-11-28 03:11:16 +00:00
# if (word-slice == '}') abort
(slice-equal? %ecx "}") # => eax
2020-02-17 23:26:49 +00:00
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
2020-02-02 01:05:59 +00:00
# v->block-depth is implicitly 0
2019-11-28 03:11:16 +00:00
#
# 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
2020-02-23 08:35:02 +00:00
# push(vars, v)
2020-04-28 05:53:28 +00:00
(push *(ebp+0x10) *ebx)
(push *(ebp+0x10) *(ebx+4))
#
2019-11-28 03:11:16 +00:00
e9/jump loop/disp32
}
# save function outputs
{
$populate-mu-function-header:check-for-out:
(next-mu-token *(ebp+8) %ecx)
2019-11-28 03:11:16 +00:00
# if (word-slice == '{') break
(slice-equal? %ecx "{") # => eax
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
0f 85/jump-if-!= break/disp32
2019-11-28 03:11:16 +00:00
# if (word-slice == '->') abort
(slice-equal? %ecx "->") # => eax
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
2019-11-28 03:11:16 +00:00
# if (word-slice == '}') abort
(slice-equal? %ecx "}") # => eax
2020-02-17 23:26:49 +00:00
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
#
2019-11-28 03:11:16 +00:00
e9/jump loop/disp32
}
$populate-mu-function-header:done:
2019-11-29 23:35:28 +00:00
(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> {'")
2019-11-28 03:11:16 +00:00
(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
2019-11-29 09:24:03 +00:00
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")
2020-01-27 08:36:44 +00:00
# var result/ecx: function
2b/subtract *Function-size 4/r32/esp
2019-11-29 09:24:03 +00:00
89/<- %ecx 4/r32/esp
(zero-out %ecx *Function-size)
2020-04-24 00:31:28 +00:00
# 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
2019-11-29 09:24:03 +00:00
# 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
2019-11-29 09:24:03 +00:00
# . 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")
2020-05-09 23:28:18 +00:00
# result/ecx: function
2b/subtract *Function-size 4/r32/esp
2019-11-29 09:24:03 +00:00
89/<- %ecx 4/r32/esp
(zero-out %ecx *Function-size)
2020-04-24 00:31:28 +00:00
# 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
2019-11-29 09:24:03 +00:00
# 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
2019-11-29 09:24:03 +00:00
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
test-function-header-with-multiple-args-and-outputs:
2019-11-29 09:24:03 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(clear-stream _test-input-stream)
2020-01-27 08:36:44 +00:00
(write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx: int {\n")
2020-05-09 23:28:18 +00:00
# result/ecx: function
2b/subtract *Function-size 4/r32/esp
2019-11-29 09:24:03 +00:00
89/<- %ecx 4/r32/esp
(zero-out %ecx *Function-size)
2020-04-24 00:31:28 +00:00
# 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
2019-11-29 09:24:03 +00:00
# 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
2019-11-29 09:24:03 +00:00
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
# format for variables with types
2020-01-27 08:36:44 +00:00
# x: int
2019-11-29 08:31:29 +00:00
# x: int,
# x/eax: int
# x/eax: int,
# ignores at most one trailing comma
# WARNING: modifies name
2020-04-24 01:38:37 +00:00
parse-var-with-type: # name: (addr slice), first-line: (addr stream byte), out: (addr handle var)
# pseudocode:
2020-01-27 08:36:44 +00:00
# var s: slice
# if (!slice-ends-with(name, ":"))
# abort
# --name->end to skip ':'
# next-token-from-slice(name->start, name->end, '/', s)
2020-04-24 01:38:37 +00:00
# new-var-from-slice(s, out)
# ## register
# next-token-from-slice(s->end, name->end, '/', s)
# if (!slice-empty?(s))
2020-04-24 01:38:37 +00:00
# out->register = slice-to-string(s)
# ## type
2020-01-27 08:36:44 +00:00
# var type: (handle tree type-id) = parse-type(first-line)
2020-04-24 01:38:37 +00:00
# out->type = type
#
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
2020-04-24 01:46:10 +00:00
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)
2020-01-27 08:36:44 +00:00
# var s/ecx: slice
68/push 0/imm32/end
68/push 0/imm32/start
89/<- %ecx 4/r32/esp
2020-03-10 21:07:15 +00:00
$parse-var-with-type:parse-name:
(next-token-from-slice *esi *(esi+4) 0x2f %ecx) # Slice-start, Slice-end, '/'
2020-03-10 21:07:15 +00:00
$parse-var-with-type:create-var:
2020-04-24 01:38:37 +00:00
# new-var-from-slice(s, out)
(new-var-from-slice Heap %ecx *(ebp+0x10))
# save out->register
$parse-var-with-type:save-register:
2020-05-04 02:14:49 +00:00
# . var out-addr/edi: (addr var) = lookup(*out)
2020-04-24 01:46:10 +00:00
8b/-> *(ebp+0x10) 7/r32/edi
(lookup *edi *(edi+4)) # => eax
89/<- %edi 0/r32/eax
# . s = next-token(...)
2020-03-10 21:07:15 +00:00
(next-token-from-slice *(ecx+4) *(esi+4) 0x2f %ecx) # s->end, name->end, '/'
2020-04-24 01:46:10 +00:00
# . if (!slice-empty?(s)) out->register = slice-to-string(s)
{
$parse-var-with-type:write-register:
2020-02-17 04:14:32 +00:00
(slice-empty? %ecx) # => eax
3d/compare-eax-and 0/imm32/false
75/jump-if-!= break/disp8
2020-04-24 01:57:15 +00:00
# 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:
2020-04-24 06:10:31 +00:00
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
2020-04-24 01:46:10 +00:00
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
2020-04-24 04:10:07 +00:00
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 != "("
2020-04-24 04:10:07 +00:00
# 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)
#
2019-11-29 08:43:10 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
2020-04-24 04:10:07 +00:00
50/push-eax
51/push-ecx
52/push-edx
2020-04-24 04:10:07 +00:00
# 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 != ""
2020-04-24 04:10:07 +00:00
(slice-equal? %ecx "") # => eax
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
2020-01-27 09:41:25 +00:00
0f 85/jump-if-!= $parse-type:abort/disp32
# assert s != "{"
2020-04-24 04:10:07 +00:00
(slice-equal? %ecx "{") # => eax
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
2020-01-27 09:41:25 +00:00
0f 85/jump-if-!= $parse-type:abort/disp32
# assert s != "}"
2020-04-24 04:10:07 +00:00
(slice-equal? %ecx "}") # => eax
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
2020-01-27 09:41:25 +00:00
0f 85/jump-if-!= $parse-type:abort/disp32
# assert s != "->"
2020-04-24 04:10:07 +00:00
(slice-equal? %ecx "->") # => eax
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
2020-01-27 09:41:25 +00:00
0f 85/jump-if-!= $parse-type:abort/disp32
# if (s == ")") return
2020-04-24 04:10:07 +00:00
(slice-equal? %ecx ")") # => eax
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
2020-01-27 09:41:25 +00:00
0f 85/jump-if-!= $parse-type:end/disp32
2020-04-24 04:10:07 +00:00
# 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
2019-11-29 08:43:10 +00:00
{
# if (s != "(") break
2020-04-24 04:10:07 +00:00
(slice-equal? %ecx "(") # => eax
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
2020-01-27 09:41:25 +00:00
75/jump-if-!= break/disp8
2020-03-12 02:55:45 +00:00
# EGREGIOUS HACK for static array sizes: if s is a number, parse it
{
$parse-type:check-for-int:
2020-03-12 02:55:45 +00:00
(is-hex-int? %ecx) # => eax
3d/compare-eax-and 0/imm32/false
74/jump-if-= break/disp8
$parse-type:int:
2020-03-12 02:55:45 +00:00
(parse-hex-int-from-slice %ecx) # => eax
2020-04-24 04:10:07 +00:00
89/<- *(edx+4) 0/r32/eax # Tree-value
e9/jump $parse-type:end/disp32
2020-03-12 02:55:45 +00:00
}
2020-04-12 09:33:01 +00:00
$parse-type:atom:
# out->left-is-atom? = true
2020-04-12 09:33:01 +00:00
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
2020-04-12 09:33:01 +00:00
89/<- *(edx+4) 0/r32/eax # Tree-value
2020-04-24 04:10:07 +00:00
e9/jump $parse-type:end/disp32
2019-11-29 08:43:10 +00:00
}
2020-04-12 09:33:01 +00:00
$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
2019-11-29 08:43:10 +00:00
# . restore registers
5a/pop-to-edx
59/pop-to-ecx
2020-04-24 04:10:07 +00:00
58/pop-to-eax
2019-11-29 08:43:10 +00:00
# . 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
2020-04-24 06:07:52 +00:00
parse-type-tree: # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle tree type-id)
2020-01-20 10:08:12 +00:00
# pseudocode:
# var tmp: (handle tree type-id) = parse-type(ad, in)
# if tmp == 0
# return 0
2020-04-24 06:07:52 +00:00
# out = allocate(Tree)
# out->left = tmp
# out->right = parse-type-tree(ad, in)
2020-01-20 10:08:12 +00:00
#
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
2020-04-24 06:07:52 +00:00
50/push-eax
51/push-ecx
2020-01-20 10:08:12 +00:00
52/push-edx
2020-04-24 06:07:52 +00:00
#
(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
2020-01-27 09:41:25 +00:00
74/jump-if-= $parse-type-tree:end/disp8
2020-04-24 06:07:52 +00:00
# out = new tree
(allocate *(ebp+8) *Tree-size *(ebp+0x10))
2020-05-04 02:14:49 +00:00
# var out-addr/edx: (addr tree) = lookup(*out)
2020-04-24 06:07:52 +00:00
8b/-> *(ebp+0x10) 2/r32/edx
(lookup *edx *(edx+4)) # => eax
2020-01-20 10:08:12 +00:00
89/<- %edx 0/r32/eax
2020-04-24 06:07:52 +00:00
# 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)
2020-01-20 10:08:12 +00:00
$parse-type-tree:end:
2020-04-24 06:07:52 +00:00
# . reclaim locals
81 0/subop/add %esp 8/imm32
2020-01-20 10:08:12 +00:00
# . restore registers
5a/pop-to-edx
59/pop-to-ecx
2020-04-24 06:07:52 +00:00
58/pop-to-eax
2020-01-20 10:08:12 +00:00
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
next-mu-token: # in: (addr stream byte), out: (addr slice)
# pseudocode:
# start:
2020-01-27 07:44:40 +00:00
# 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
2020-01-20 10:42:08 +00:00
# curr-byte = in->data[in->read]
# if curr-byte == ' '
# break
2020-01-27 07:44:40 +00:00
# if curr-byte == '\r'
# break
# if curr-byte == '\n'
# break
2020-01-20 10:42:08 +00:00
# if curr-byte == '('
# break
2020-01-20 10:42:08 +00:00
# if curr-byte == ')'
# break
2020-01-20 10:42:08 +00:00
# if curr-byte == ','
# break
2020-01-20 10:42:08 +00:00
# ++in->read
# done:
# out->end = &in->data[in->read]
#
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
2020-01-13 04:25:11 +00:00
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:
2020-01-27 07:44:40 +00:00
(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
2020-01-27 08:36:44 +00:00
# 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
}
{
2020-01-20 10:42:08 +00:00
$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
2020-01-27 07:44:40 +00:00
# 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
2020-01-20 10:42:08 +00:00
# ++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
2020-01-13 04:25:11 +00:00
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
2020-02-25 06:46:45 +00:00
# . 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
2020-03-09 01:11:19 +00:00
$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
2020-02-25 06:46:45 +00:00
(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
2020-02-25 06:46:45 +00:00
# . 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
2020-01-09 08:06:38 +00:00
# index is denominated in elements, not bytes
pos-slice: # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
2020-01-09 08:06:38 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
51/push-ecx
52/push-edx
53/push-ebx
56/push-esi
2020-01-20 11:05:31 +00:00
#? (write-buffered Stderr "pos-slice: ")
#? (write-slice-buffered Stderr *(ebp+0xc))
#? (write-buffered Stderr "\n")
#? (flush Stderr)
2020-01-09 08:06:38 +00:00
# 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)
2020-01-09 08:06:38 +00:00
# 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
2020-01-09 08:06:38 +00:00
# if (slice-equal?(s, *curr)) break
(slice-equal? *(ebp+0xc) *edx) # => eax
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
75/jump-if-!= break/disp8
2020-01-09 08:06:38 +00:00
# ++index
41/increment-ecx
# curr += 4
81 0/subop/add %edx 4/imm32
#
eb/jump loop/disp8
2020-01-09 08:06:38 +00:00
}
# return index
2020-01-09 08:06:38 +00:00
89/<- %eax 1/r32/ecx
$pos-slice:end:
2020-01-20 11:05:31 +00:00
#? (write-buffered Stderr "=> ")
#? (print-int32-buffered Stderr %eax)
#? (write-buffered Stderr "\n")
2020-01-09 08:06:38 +00:00
# . 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
2020-01-27 08:36:44 +00:00
# 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")
2020-05-10 23:50:06 +00:00
# var v/edx: (handle var)
68/push 0/imm32
68/push 0/imm32
89/<- %edx 4/r32/esp
#
2020-05-10 23:50:06 +00:00
(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
2020-01-27 08:36:44 +00:00
# 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")
2020-05-10 23:50:06 +00:00
# var v/edx: (handle var)
68/push 0/imm32
68/push 0/imm32
89/<- %edx 4/r32/esp
#
2020-05-10 23:50:06 +00:00
(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
2019-11-29 08:31:29 +00:00
test-parse-var-with-trailing-characters:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# (eax..ecx) = "x:"
b8/copy-to-eax "x:"/imm32
2019-11-29 08:31:29 +00:00
8b/-> *eax 1/r32/ecx
8d/copy-address *(eax+ecx+4) 1/r32/ecx
05/add-to-eax 4/imm32
2020-01-27 08:36:44 +00:00
# var slice/ecx: slice = {eax, ecx}
2019-11-29 08:31:29 +00:00
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,")
2020-05-10 23:50:06 +00:00
# var v/edx: (handle var)
68/push 0/imm32
68/push 0/imm32
89/<- %edx 4/r32/esp
2019-11-29 08:31:29 +00:00
#
2020-05-10 23:50:06 +00:00
(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
2019-11-29 08:31:29 +00:00
# . 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
2020-01-27 08:36:44 +00:00
# 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,")
2020-05-10 23:50:06 +00:00
# var v/edx: (handle var)
68/push 0/imm32
68/push 0/imm32
89/<- %edx 4/r32/esp
#
2020-05-10 23:50:06 +00:00
(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
2020-01-27 08:36:44 +00:00
# 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)")
2020-05-10 23:50:06 +00:00
# var v/edx: (handle var)
68/push 0/imm32
68/push 0/imm32
89/<- %edx 4/r32/esp
#
2020-05-10 23:50:06 +00:00
(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
2020-04-12 09:33:01 +00:00
# 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)
2020-05-10 23:50:06 +00:00
(lookup *(edx+4) *(edx+8)) # Tree-left Tree-left => eax
2020-04-12 09:33:01 +00:00
(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)
2020-05-10 23:50:06 +00:00
(lookup *(edx+0xc) *(edx+0x10)) # Tree-right Tree-right => eax
(lookup *(eax+4) *(eax+8)) # Tree-left Tree-left => eax
2020-04-12 09:33:01 +00:00
(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
2020-05-10 23:50:06 +00:00
(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
2019-11-28 09:01:37 +00:00
# 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 '->'
2020-01-27 08:36:44 +00:00
is-identifier?: # in: (addr slice) -> result/eax: boolean
2019-11-28 09:01:37 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# if (slice-empty?(in)) return false
(slice-empty? *(ebp+8)) # => eax
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
75/jump-if-!= $is-identifier?:false/disp8
2020-01-27 08:36:44 +00:00
# var c/eax: byte = *in->start
2019-11-28 09:01:37 +00:00
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
2019-11-28 09:01:37 +00:00
# if (c == '_') return true
3d/compare-eax-and 0x5f/imm32/_
74/jump-if-= $is-identifier?:true/disp8
2019-11-28 09:01:37 +00:00
# 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
2019-11-28 09:01:37 +00:00
# if (c > 'Z') return false
3d/compare-eax-and 0x5a/imm32/Z
7f/jump-if-> $is-identifier?:false/disp8
2019-11-28 09:01:37 +00:00
# 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
2020-01-27 08:36:44 +00:00
# var slice/ecx: slice = {eax, ecx}
2019-11-28 09:01:37 +00:00
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
2020-01-27 08:36:44 +00:00
# var slice/ecx: slice = {eax, ecx}
2019-11-28 09:01:37 +00:00
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
2020-01-27 08:36:44 +00:00
# var slice/ecx: slice = {eax, ecx}
2019-11-28 09:01:37 +00:00
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
2020-01-27 08:36:44 +00:00
# var slice/ecx: slice = {eax, ecx}
2019-11-28 09:01:37 +00:00
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
2020-01-27 08:36:44 +00:00
# var slice/ecx: slice = {eax, ecx}
2019-11-28 09:01:37 +00:00
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
2020-01-27 08:36:44 +00:00
# var slice/ecx: slice = {eax, ecx}
2019-11-28 09:01:37 +00:00
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
2020-05-10 23:55:03 +00:00
test-is-identifier-at:
2019-11-28 09:13:44 +00:00
# character before 'A' is invalid
2019-11-28 09:01:37 +00:00
# . 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
2020-01-27 08:36:44 +00:00
# var slice/ecx: slice = {eax, ecx}
2019-11-28 09:01:37 +00:00
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
2019-11-28 09:13:44 +00:00
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
2020-01-27 08:36:44 +00:00
# var slice/ecx: slice = {eax, ecx}
2019-11-28 09:13:44 +00:00
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
2020-01-27 08:36:44 +00:00
# var slice/ecx: slice = {eax, ecx}
2019-11-28 09:13:44 +00:00
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
2020-01-27 08:36:44 +00:00
# var slice/ecx: slice = {eax, ecx}
2019-11-28 09:13:44 +00:00
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
2020-01-27 08:36:44 +00:00
# var slice/ecx: slice = {eax, ecx}
2019-11-28 09:13:44 +00:00
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
2020-01-27 08:36:44 +00:00
# var slice/ecx: slice = {eax, ecx}
2019-11-28 09:13:44 +00:00
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
2020-04-23 02:01:17 +00:00
populate-mu-function-body: # in: (addr buffered-file), out: (addr function), vars: (addr stack (handle var))
2019-11-26 05:04:23 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
56/push-esi
57/push-edi
2019-11-26 05:04:23 +00:00
# esi = in
8b/-> *(ebp+8) 6/r32/esi
# edi = out
8b/-> *(ebp+0xc) 7/r32/edi
2020-04-28 05:53:28 +00:00
# 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)
2019-11-26 05:04:23 +00:00
$populate-mu-function-body:end:
# . restore registers
5f/pop-to-edi
2019-11-26 05:04:23 +00:00
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
2020-04-28 05:53:28 +00:00
parse-mu-block: # in: (addr buffered-file), vars: (addr stack (handle var)), fn: (addr function), out: (addr handle block)
# pseudocode:
2020-01-27 08:36:44 +00:00
# var line: (stream byte 512)
# var word-slice: slice
2020-04-28 05:53:28 +00:00
# allocate(Heap, Stmt-size, out)
2020-05-04 02:14:49 +00:00
# var out-addr: (addr block) = lookup(*out)
2020-04-28 05:53:28 +00:00
# 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, "{")
2019-11-29 23:35:28 +00:00
# assert(no-tokens-in(line))
# block = parse-mu-block(in, vars, fn)
2020-04-28 05:53:28 +00:00
# append-to-block(out-addr, block)
# else if slice-equal?(word-slice, "}")
# break
# else if slice-ends-with?(word-slice, ":")
2020-02-03 01:34:03 +00:00
# # TODO: error-check the rest of 'line'
# --word-slice->end to skip ':'
# named-block = parse-mu-named-block(word-slice, in, vars, fn)
2020-04-28 05:53:28 +00:00
# append-to-block(out-addr, named-block)
# else if slice-equal?(word-slice, "var")
# var-def = parse-mu-var-def(line, vars)
2020-04-28 05:53:28 +00:00
# append-to-block(out-addr, var-def)
# else
# stmt = parse-mu-stmt(line, vars, fn)
2020-04-28 05:53:28 +00:00
# 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
2020-01-27 08:36:44 +00:00
# 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
2020-01-27 08:36:44 +00:00
# var word-slice/edx: slice
68/push 0/imm32/end
68/push 0/imm32/start
89/<- %edx 4/r32/esp
2020-04-28 05:53:28 +00:00
# allocate into out
(allocate Heap *Stmt-size *(ebp+0x14))
2020-05-04 02:14:49 +00:00
# var out-addr/edi: (addr block) = lookup(*out)
2020-04-28 05:53:28 +00:00
8b/-> *(ebp+0x14) 7/r32/edi
(lookup *edi *(edi+4)) # => eax
89/<- %edi 0/r32/eax
2020-04-28 05:53:28 +00:00
# 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
{
2019-11-26 05:04:23 +00:00
$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)
2019-11-03 07:43:37 +00:00
# if slice-empty?(word-slice) continue
(slice-empty? %edx)
2020-02-17 23:26:49 +00:00
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 "{")
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
74/jump-if-= break/disp8
2019-11-29 23:35:28 +00:00
(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 "}")
2020-02-17 23:26:49 +00:00
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")
2020-02-17 23:26:49 +00:00
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
2019-11-26 05:04:23 +00:00
$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
2019-11-26 05:04:23 +00:00
$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
2020-04-28 05:53:28 +00:00
new-block-name: # fn: (addr function), out: (addr handle var)
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
2020-04-28 05:53:28 +00:00
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
2020-05-18 00:59:12 +00:00
(lookup *eax *(eax+4)) # Function-name Function-name => eax
8b/-> *eax 0/r32/eax # String-size
05/add-to-eax 0xd/imm32 # 10 + 2 for '$:'
89/<- %ecx 0/r32/eax
# var name/edx: (stream byte n)
29/subtract-from %esp 1/r32/ecx
ff 6/subop/push %ecx
68/push 0/imm32/read
68/push 0/imm32/write
89/<- %edx 4/r32/esp
(clear-stream %edx)
# eax = fn->name
8b/-> *(ebp+8) 0/r32/eax
2020-05-18 00:59:12 +00:00
(lookup *eax *(eax+4)) # Function-name Function-name => eax
# construct result using Next-block-index (and increment it)
(write %edx "$")
(write %edx %eax)
(write %edx ":")
(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
2020-04-28 05:53:28 +00:00
# out = new literal(s)
(new-literal Heap %eax *(ebp+0xc))
#? 8b/-> *(ebp+0xc) 0/r32/eax
#? (write-buffered Stderr "type allocid in caller after new-literal: ")
#? (print-int32-buffered Stderr *(eax+8))
#? (write-buffered Stderr " for var ")
#? (print-int32-buffered Stderr %eax)
#? (write-buffered Stderr Newline)
#? (flush Stderr)
$new-block-name:end:
# . reclaim locals
81 0/subop/add %ecx 0xc/imm32 # name.{read/write/len}
81 0/subop/add %ecx 8/imm32 # slice
01/add-to %esp 1/r32/ecx
# . restore registers
5a/pop-to-edx
59/pop-to-ecx
2020-04-28 05:53:28 +00:00
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
2020-01-27 08:36:44 +00:00
check-no-tokens-left: # line: (addr stream byte)
2019-11-29 23:35:28 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
51/push-ecx
2020-01-27 08:36:44 +00:00
# var s/ecx: slice
2019-11-29 23:35:28 +00:00
68/push 0/imm32/end
68/push 0/imm32/start
89/<- %ecx 4/r32/esp
#
(next-mu-token *(ebp+8) %ecx)
2019-11-29 23:35:28 +00:00
# if slice-empty?(s) return
(slice-empty? %ecx)
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
75/jump-if-!= $check-no-tokens-left:end/disp8
2019-11-29 23:35:28 +00:00
# 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
2019-11-29 23:35:28 +00:00
# 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
2020-02-22 04:17:12 +00:00
# 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
2020-05-04 00:06:13 +00:00
50/push-eax
2020-01-27 07:44:40 +00:00
51/push-ecx
52/push-edx
2020-05-04 00:06:13 +00:00
57/push-edi
# edi = out
8b/-> *(ebp+0x10) 7/r32/edi
2020-01-27 08:36:44 +00:00
# var word-slice/ecx: slice
2020-01-27 07:44:40 +00:00
68/push 0/imm32/end
68/push 0/imm32/start
89/<- %ecx 4/r32/esp
2020-05-04 00:06:13 +00:00
# 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)
2020-05-04 00:06:13 +00:00
(parse-var-with-type %ecx *(ebp+8) %edx)
2020-01-27 10:07:00 +00:00
#
2020-05-04 00:06:13 +00:00
(push *(ebp+0xc) *edx)
(push *(ebp+0xc) *(edx+4))
2020-01-27 07:44:40 +00:00
# either v has no register and there's no more to this line
2020-05-04 00:06:13 +00:00
(lookup *edx *(edx+4)) # => eax
8b/-> *(eax+0x18) 0/r32/eax # Var-register
2020-01-27 07:44:40 +00:00
3d/compare-eax-and 0/imm32
{
2020-01-27 09:41:25 +00:00
75/jump-if-!= break/disp8
2020-01-27 07:44:40 +00:00
# TODO: ensure that there's nothing else on this line
2020-05-04 00:06:13 +00:00
(new-var-def Heap *edx *(edx+4) %edi)
2020-01-27 07:44:40 +00:00
eb/jump $parse-mu-var-def:end/disp8
}
# or v has a register and there's more to this line
{
2020-01-27 09:41:25 +00:00
74/jump-if-= break/disp8
2020-01-27 07:44:40 +00:00
# ensure that the next word is '<-'
(next-mu-token *(ebp+8) %ecx)
2020-01-27 07:44:40 +00:00
(slice-equal? %ecx "<-") # => eax
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
2020-01-27 09:41:25 +00:00
74/jump-if-= $parse-mu-var-def:abort/disp8
2020-01-27 07:44:40 +00:00
#
2020-05-04 00:06:13 +00:00
(new-reg-var-def Heap *edx *(edx+4) %edi)
(lookup *edi *(edi+4)) # => eax
2020-01-27 07:44:40 +00:00
(add-operation-and-inputs-to-stmt %eax *(ebp+8) *(ebp+0xc))
}
$parse-mu-var-def:end:
# . reclaim locals
2020-05-04 00:06:13 +00:00
81 0/subop/add %esp 0x10/imm32
# . restore registers
2020-05-04 00:06:13 +00:00
5f/pop-to-edi
2020-01-27 07:44:40 +00:00
5a/pop-to-edx
59/pop-to-ecx
2020-05-04 00:06:13 +00:00
58/pop-to-eax
2020-01-27 07:44:40 +00:00
# . 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
2020-04-24 00:31:28 +00:00
# var vars/ecx: (stack (addr var) 16)
81 5/subop/subtract %esp 0x80/imm32
68/push 0x80/imm32/size
2020-01-27 07:44:40 +00:00
68/push 0/imm32/top
89/<- %ecx 4/r32/esp
(clear-stack %ecx)
# convert
(parse-mu-var-def _test-input-stream %ecx %esi)
2020-05-05 05:55:48 +00:00
# var out-addr/esi: (addr stmt)
(lookup *esi *(esi+4)) # => eax
89/<- %esi 0/r32/eax
2020-05-05 05:55:48 +00:00
#
(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)
2020-05-05 05:55:48 +00:00
(lookup *(esi+4) *(esi+8)) # Vardef-var Vardef-var => eax
89/<- %ecx 0/r32/eax
# v->name
2020-05-05 05:55:48 +00:00
(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
2020-05-05 05:55:48 +00:00
(lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax
2020-04-12 09:33:01 +00:00
(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
2020-01-27 07:44:40 +00:00
# . 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'
2020-05-05 05:55:48 +00:00
# var out/esi: (handle stmt)
68/push 0/imm32
68/push 0/imm32
2020-05-05 05:55:48 +00:00
89/<- %esi 4/r32/esp
2020-04-24 00:31:28 +00:00
# var vars/ecx: (stack (addr var) 16)
81 5/subop/subtract %esp 0x80/imm32
68/push 0x80/imm32/size
2020-01-27 07:44:40 +00:00
68/push 0/imm32/top
89/<- %ecx 4/r32/esp
(clear-stack %ecx)
# convert
2020-05-05 05:55:48 +00:00
(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
2020-05-05 06:53:30 +00:00
(lookup *(ecx+0x18) *(ecx+0x1c)) # Var-register Var-register => eax
(check-strings-equal %eax "eax" "F - test-parse-mu-reg-var-def/output-register")
2020-05-05 05:55:48 +00:00
# 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:
2020-01-27 08:36:44 +00:00
# var name: slice
2020-05-03 23:50:09 +00:00
# allocate(Heap, Stmt-size, out)
# var out-addr: (addr stmt) = lookup(*out)
# out-addr->tag = stmt
# if stmt-has-outputs?(line)
# while true
2020-01-27 22:14:40 +00:00
# name = next-mu-token(line)
# if (name == '<-') break
# assert(is-identifier?(name))
2020-01-27 08:36:44 +00:00
# var v: (handle var) = lookup-or-define-var(name, vars, fn) # regular stmts may define vars in fn outputs
2020-05-03 23:50:09 +00:00
# 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
2020-05-03 23:50:09 +00:00
50/push-eax
51/push-ecx
52/push-edx
2020-05-03 23:50:09 +00:00
53/push-ebx
57/push-edi
2020-01-27 08:36:44 +00:00
# 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
2020-05-03 23:50:09 +00:00
# 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
2020-05-03 23:50:09 +00:00
# out-addr->tag = 1/stmt
c7 0/subop/copy *edi 1/imm32/stmt1 # Stmt-tag
{
(stmt-has-outputs? *(ebp+8))
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
0f 84/jump-if-= break/disp32
{
$parse-mu-stmt:read-outputs:
2020-01-27 22:14:40 +00:00
# name = next-mu-token(line)
(next-mu-token *(ebp+8) %ecx)
# if slice-empty?(word-slice) break
(slice-empty? %ecx) # => eax
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
0f 85/jump-if-!= break/disp32
# if (name == "<-") break
(slice-equal? %ecx "<-") # => eax
2020-02-17 23:26:49 +00:00
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
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
0f 84/jump-if-= $parse-mu-stmt:abort/disp32
2020-05-03 23:50:09 +00:00
#
(lookup-or-define-var %ecx *(ebp+0xc) *(ebp+0x10) %ebx)
8d/copy-address *(edi+0x14) 0/r32/eax # Stmt1-outputs
2020-05-03 23:50:09 +00:00
(append-stmt-var Heap *ebx *(ebx+4) *(edi+0x14) *(edi+0x18) %edx %eax) # Stmt1-outputs
#
e9/jump loop/disp32
}
}
2020-01-26 23:09:57 +00:00
(add-operation-and-inputs-to-stmt %edi *(ebp+8) *(ebp+0xc))
$parse-mu-stmt:end:
# . reclaim locals
2020-05-03 23:50:09 +00:00
81 0/subop/add %esp 0x10/imm32
# . restore registers
5f/pop-to-edi
2020-05-03 23:50:09 +00:00
5b/pop-to-ebx
5a/pop-to-edx
59/pop-to-ecx
2020-05-03 23:50:09 +00:00
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))
2020-01-26 23:09:57 +00:00
# pseudocode:
2020-01-27 22:14:40 +00:00
# stmt->name = slice-to-string(next-mu-token(line))
2020-01-26 23:09:57 +00:00
# while true
2020-01-27 22:14:40 +00:00
# name = next-mu-token(line)
2020-01-26 23:09:57 +00:00
# v = lookup-var-or-literal(name)
# stmt->inouts = append(v, stmt->inouts)
2020-01-26 23:09:57 +00:00
#
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
2020-01-27 07:44:40 +00:00
50/push-eax
2020-01-26 23:09:57 +00:00
51/push-ecx
52/push-edx
53/push-ebx
56/push-esi
2020-01-26 23:09:57 +00:00
57/push-edi
# edi = stmt
8b/-> *(ebp+8) 7/r32/edi
2020-01-27 08:36:44 +00:00
# var name/ecx: slice
2020-01-26 23:09:57 +00:00
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
2020-01-26 23:09:57 +00:00
$add-operation-and-inputs-to-stmt:read-operation:
2020-01-27 22:14:40 +00:00
(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
2020-01-26 23:09:57 +00:00
{
$add-operation-and-inputs-to-stmt:read-inouts:
2020-01-27 22:14:40 +00:00
# name = next-mu-token(line)
(next-mu-token *(ebp+0xc) %ecx)
2020-01-26 23:09:57 +00:00
# if slice-empty?(word-slice) break
(slice-empty? %ecx) # => eax
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
2020-01-26 23:09:57 +00:00
0f 85/jump-if-!= break/disp32
# if (name == "<-") abort
(slice-equal? %ecx "<-")
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
2020-01-26 23:09:57 +00:00
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
2020-05-22 21:43:26 +00:00
(lookup *(edi+0xc) *(edi+0x10)) # Stmt1-inouts Stmt1-inouts => eax
3d/compare-eax-and 0/imm32
74/jump-if-= break/disp8
2020-05-22 21:43:26 +00:00
(lookup-or-create-constant %eax %ecx %esi)
2020-05-24 07:51:52 +00:00
#? (lookup *esi *(esi+4))
#? (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 "; var name ")
#? (lookup *eax *(eax+4)) # Var-name
#? (write-buffered Stderr %eax)
#? (write-buffered Stderr Newline)
#? (flush Stderr)
e9/jump $add-operation-and-inputs-to-stmt:save-var/disp32
}
# is-deref? = false
ba/copy-to-edx 0/imm32/false
# if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
8b/-> *ecx 0/r32/eax # Slice-start
8a/copy-byte *eax 0/r32/AL
81 4/subop/and %eax 0xff/imm32
3d/compare-eax-and 0x2a/imm32/asterisk
{
75/jump-if-!= break/disp8
$add-operation-and-inputs-to-stmt:inout-is-deref:
ff 0/subop/increment *ecx
ba/copy-to-edx 1/imm32/true
}
(lookup-var-or-literal %ecx *(ebp+0x10) %esi)
2020-02-23 08:35:02 +00:00
$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
#
2020-01-26 23:09:57 +00:00
e9/jump loop/disp32
}
$add-operation-and-inputs-to-stmt:end:
# . reclaim locals
81 0/subop/add %esp 0x10/imm32
2020-01-26 23:09:57 +00:00
# . restore registers
5f/pop-to-edi
5e/pop-to-esi
5b/pop-to-ebx
5a/pop-to-edx
2020-01-26 23:09:57 +00:00
59/pop-to-ecx
2020-01-27 07:44:40 +00:00
58/pop-to-eax
2020-01-26 23:09:57 +00:00
# . 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 '")
2020-01-27 07:44:40 +00:00
(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
2020-01-27 08:36:44 +00:00
stmt-has-outputs?: # line: (addr stream byte) -> result/eax: boolean
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
51/push-ecx
2020-01-27 08:36:44 +00:00
# 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))
{
2020-01-27 22:14:40 +00:00
(next-mu-token *(ebp+8) %ecx)
# if slice-empty?(word-slice) break
(slice-empty? %ecx)
2020-02-17 23:26:49 +00:00
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 "<-")
2020-02-17 23:26:49 +00:00
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
2020-01-01 05:58:52 +00:00
# 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)
2020-01-01 05:58:52 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
2020-05-05 05:55:48 +00:00
50/push-eax
2020-01-01 05:58:52 +00:00
51/push-ecx
56/push-esi
# esi = name
8b/-> *(ebp+8) 6/r32/esi
# if slice-empty?(name) abort
(slice-empty? %esi) # => eax
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32
2020-01-30 09:16:59 +00:00
# var c/ecx: byte = *name->start
2020-01-01 05:58:52 +00:00
8b/-> *esi 1/r32/ecx
8a/copy-byte *ecx 1/r32/CL
81 4/subop/and %ecx 0xff/imm32
2020-01-30 09:16:59 +00:00
# if is-decimal-digit?(c) return new var(name)
2020-01-01 05:58:52 +00:00
{
2020-01-30 09:16:59 +00:00
(is-decimal-digit? %ecx) # => eax
2020-02-22 03:38:11 +00:00
3d/compare-eax-and 0/imm32/false
74/jump-if-= break/disp8
2020-05-05 05:55:48 +00:00
(new-literal-integer Heap %esi *(ebp+0x10))
2020-01-30 09:16:59 +00:00
eb/jump $lookup-var-or-literal:end/disp8
2020-01-01 05:58:52 +00:00
}
2020-01-30 09:16:59 +00:00
# else if (c == '"') return new var(name)
2020-01-01 05:58:52 +00:00
{
2020-01-30 09:16:59 +00:00
81 7/subop/compare %ecx 0x22/imm32/dquote
75/jump-if-!= break/disp8
2020-05-05 05:55:48 +00:00
(new-literal Heap %esi *(ebp+0x10))
2020-01-30 09:16:59 +00:00
eb/jump $lookup-var-or-literal:end/disp8
}
# otherwise return lookup-var(name, vars)
{
2020-01-01 05:58:52 +00:00
(lookup-var %esi *(ebp+0xc)) # => eax
}
$lookup-var-or-literal:end:
# . restore registers
5e/pop-to-esi
59/pop-to-ecx
2020-05-05 05:55:48 +00:00
58/pop-to-eax
2020-01-01 05:58:52 +00:00
# . 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
2019-12-30 09:33:34 +00:00
# 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)
2019-12-28 03:10:34 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
2019-12-28 03:10:34 +00:00
#
(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
2019-12-28 03:10:34 +00:00
$lookup-var:end:
# . restore registers
58/pop-to-eax
2019-12-28 03:10:34 +00:00
# . 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
2019-12-30 09:33:34 +00:00
# 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
2020-01-27 08:36:44 +00:00
# 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
2020-05-05 23:35:41 +00:00
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
2020-01-27 08:36:44 +00:00
# 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
{
2020-05-05 23:35:41 +00:00
# if (curr < min) return
39/compare %ebx 2/r32/edx
0f 82/jump-if-addr< break/disp32
2020-05-05 23:35:41 +00:00
# var v/ecx: (addr var) = lookup(*curr)
(lookup *ebx *(ebx+4)) # => eax
2020-05-05 23:35:41 +00:00
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
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
2020-05-05 23:35:41 +00:00
{
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
}
2019-12-28 03:10:34 +00:00
$lookup-var-helper:end:
# . restore registers
5e/pop-to-esi
5b/pop-to-ebx
5a/pop-to-edx
2020-05-05 23:35:41 +00:00
59/pop-to-ecx
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
2019-12-28 03:10:34 +00:00
$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
2019-12-30 09:33:34 +00:00
# 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
2020-05-05 22:11:04 +00:00
50/push-eax
#
2020-05-05 22:11:04 +00:00
(lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x14))
{
2020-05-05 22:11:04 +00:00
# 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
{
2020-05-05 22:11:04 +00:00
(find-in-function-outputs *(ebp+0x10) *(ebp+8) *(ebp+0x14))
2020-05-18 05:50:58 +00:00
8b/-> *(ebp+0x14) 0/r32/eax
2020-05-05 22:11:04 +00:00
81 7/subop/compare *eax 0/imm32
# otherwise abort
2020-05-05 22:11:04 +00:00
0f 84/jump-if-= $lookup-var:abort/disp32
}
}
$lookup-or-define-var:end:
# . restore registers
2020-05-05 22:11:04 +00:00
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
2020-05-06 21:24:37 +00:00
50/push-eax
51/push-ecx
2020-05-06 21:24:37 +00:00
# var curr/ecx: (addr list var) = lookup(fn->outputs)
8b/-> *(ebp+8) 1/r32/ecx
2020-05-18 05:50:58 +00:00
(lookup *(ecx+0x10) *(ecx+0x14)) # Function-outputs Function-outputs => eax
2020-05-06 21:24:37 +00:00
89/<- %ecx 0/r32/eax
# while curr != null
{
81 7/subop/compare %ecx 0/imm32
74/jump-if-= break/disp8
2020-05-06 21:24:37 +00:00
# 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
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
2020-05-06 21:24:37 +00:00
{
74/jump-if-= break/disp8
# var edi = out
57/push-edi
2020-05-18 05:50:58 +00:00
8b/-> *(ebp+0x10) 7/r32/edi
2020-05-06 21:24:37 +00:00
# *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
2020-05-06 21:24:37 +00:00
(lookup *(ecx+8) *(ecx+0xc)) # List-next List-next => eax
89/<- %ecx 0/r32/eax
2020-05-07 06:05:13 +00:00
#
eb/jump loop/disp8
}
b8/copy-to-eax 0/imm32
$find-in-function-outputs:end:
# . restore registers
59/pop-to-ecx
2020-05-06 21:24:37 +00:00
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")
2020-04-24 00:31:28 +00:00
# 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)
2020-05-05 23:35:41 +00:00
# var v/edx: (handle var)
68/push 0/imm32
68/push 0/imm32
89/<- %edx 4/r32/esp
2020-05-05 23:35:41 +00:00
# var s/eax: (handle array byte)
68/push 0/imm32
68/push 0/imm32
89/<- %eax 4/r32/esp
# v = new var("n")
2020-05-05 23:35:41 +00:00
(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
2020-05-05 23:35:41 +00:00
(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
2020-01-27 22:14:40 +00:00
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")
2020-04-24 00:31:28 +00:00
# var vars/ecx: (stack (addr var) 16)
81 5/subop/subtract %esp 0x80/imm32
68/push 0x80/imm32/size
2020-01-27 22:14:40 +00:00
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
2020-01-27 22:14:40 +00:00
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)
2020-01-27 22:14:40 +00:00
#
(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
2020-01-27 22:14:40 +00:00
# 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")
2020-01-27 22:14:40 +00:00
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
2020-05-05 23:35:41 +00:00
new-var: # ad: (addr allocation-descriptor), name: (handle array byte), out: (addr handle var)
2019-11-28 00:50:23 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
2020-04-23 23:22:41 +00:00
50/push-eax
2019-11-28 00:50:23 +00:00
51/push-ecx
2020-04-23 23:22:41 +00:00
# ecx = out
2020-04-24 01:38:37 +00:00
8b/-> *(ebp+0x14) 1/r32/ecx
2019-11-28 00:50:23 +00:00
#
2020-04-23 23:22:41 +00:00
(allocate *(ebp+8) *Var-size %ecx)
# var out-addr/eax: (addr var)
(lookup *ecx *(ecx+4)) # => eax
2020-05-05 23:35:41 +00:00
# out-addr->name = name
2020-04-24 01:38:37 +00:00
8b/-> *(ebp+0xc) 1/r32/ecx
89/<- *eax 1/r32/ecx # Var-name
8b/-> *(ebp+0x10) 1/r32/ecx
89/<- *(eax+4) 1/r32/ecx # Var-name
#? (write-buffered Stderr "var ")
#? (lookup *(ebp+0xc) *(ebp+0x10))
#? (write-buffered Stderr %eax)
#? (write-buffered Stderr " at ")
#? 8b/-> *(ebp+0x14) 1/r32/ecx
#? (lookup *ecx *(ecx+4)) # => eax
#? (print-int32-buffered Stderr %eax)
#? (write-buffered Stderr Newline)
#? (flush Stderr)
2019-11-28 00:50:23 +00:00
$new-var:end:
# . restore registers
59/pop-to-ecx
2020-04-23 23:22:41 +00:00
58/pop-to-eax
2019-11-28 00:50:23 +00:00
# . 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)
2020-01-01 05:58:52 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
2020-05-05 05:55:48 +00:00
50/push-eax
2020-01-01 05:58:52 +00:00
51/push-ecx
# if (!is-hex-int?(name)) abort
(is-hex-int? *(ebp+0xc)) # => eax
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
0f 84/jump-if-= $new-literal-integer:abort/disp32
2020-05-05 05:55:48 +00:00
# out = new var(s)
(new-var-from-slice *(ebp+8) *(ebp+0xc) *(ebp+0x10))
2020-05-05 06:02:05 +00:00
# var out-addr/ecx: (addr var) = lookup(*out)
2020-05-05 05:55:48 +00:00
8b/-> *(ebp+0x10) 0/r32/eax
(lookup *eax *(eax+4)) # => eax
2020-05-05 06:02:05 +00:00
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'
2020-01-01 05:58:52 +00:00
$new-literal-integer:end:
2020-05-05 05:55:48 +00:00
# . reclaim locals
81 0/subop/add %esp 8/imm32
2020-01-01 05:58:52 +00:00
# . restore registers
59/pop-to-ecx
2020-05-05 05:55:48 +00:00
58/pop-to-eax
2020-01-01 05:58:52 +00:00
# . 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
2020-04-24 01:38:37 +00:00
new-literal: # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
2020-01-30 09:16:59 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
2020-04-24 01:38:37 +00:00
50/push-eax
2020-01-30 09:16:59 +00:00
51/push-ecx
2020-04-24 01:38:37 +00:00
# var s/ecx: (handle array byte)
68/push 0/imm32
68/push 0/imm32
2020-01-30 09:16:59 +00:00
89/<- %ecx 0/r32/eax
2020-04-24 01:38:37 +00:00
# s = slice-to-string(name)
(slice-to-string Heap *(ebp+0xc) %ecx)
# allocate to out
2020-04-28 05:55:34 +00:00
(new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
# var out-addr/ecx: (addr var) = lookup(*out)
2020-04-24 01:38:37 +00:00
8b/-> *(ebp+0x10) 1/r32/ecx
(lookup *ecx *(ecx+4)) # => eax
89/<- %ecx 0/r32/eax
# out-addr->type/eax = new type
2020-04-24 01:38:37 +00:00
8d/copy-address *(ecx+8) 0/r32/eax # Var-type
(allocate *(ebp+8) *Tree-size %eax)
2020-05-05 06:02:05 +00:00
(lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax
2020-04-22 06:41:23 +00:00
# nothing else to do; default type is 'literal'
2020-04-12 09:33:01 +00:00
c7 0/subop/copy *eax 1/imm32/true # Tree-is-atom
2020-02-22 04:17:12 +00:00
$new-literal:end:
2020-04-24 01:38:37 +00:00
# . reclaim locals
81 0/subop/add %esp 8/imm32
2020-01-30 09:16:59 +00:00
# . restore registers
59/pop-to-ecx
2020-04-24 01:38:37 +00:00
58/pop-to-eax
2020-01-30 09:16:59 +00:00
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
2020-04-24 01:38:37 +00:00
new-var-from-slice: # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
2020-01-30 01:34:07 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
51/push-ecx
2020-04-24 01:38:37 +00:00
# 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))
2020-03-10 21:07:15 +00:00
$new-var-from-slice:end:
2020-04-24 01:38:37 +00:00
# . reclaim locals
81 0/subop/add %esp 8/imm32
2020-01-30 01:34:07 +00:00
# . restore registers
59/pop-to-ecx
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
2020-05-04 00:06:13 +00:00
new-var-def: # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
2019-11-28 00:50:23 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
2020-05-04 02:14:49 +00:00
50/push-eax
2019-11-28 00:50:23 +00:00
51/push-ecx
#
2020-05-04 02:14:49 +00:00
(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
2019-11-28 00:50:23 +00:00
c7 0/subop/copy *eax 2/imm32/tag/var-on-stack # Stmt-tag
2020-01-26 22:02:54 +00:00
# result->var = var
2019-11-28 00:50:23 +00:00
8b/-> *(ebp+0xc) 1/r32/ecx
2020-01-26 22:02:54 +00:00
89/<- *(eax+4) 1/r32/ecx # Vardef-var
2020-05-04 02:14:49 +00:00
8b/-> *(ebp+0x10) 1/r32/ecx
89/<- *(eax+8) 1/r32/ecx # Vardef-var
2020-02-21 23:50:57 +00:00
$new-var-def:end:
2019-11-28 00:50:23 +00:00
# . restore registers
59/pop-to-ecx
2020-05-04 02:14:49 +00:00
58/pop-to-eax
2019-11-28 00:50:23 +00:00
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
2020-05-04 00:06:13 +00:00
new-reg-var-def: # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
2019-11-28 00:50:23 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
2020-05-04 02:26:20 +00:00
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
2020-05-04 02:26:20 +00:00
c7 0/subop/copy *eax 3/imm32/tag/var-in-register # Stmt-tag
# set output
2020-05-04 02:26:20 +00:00
8d/copy-address *(eax+0x14) 0/r32/eax # Regvardef-outputs
(append-stmt-var Heap *(ebp+0xc) *(ebp+0x10) 0 0 0 %eax)
2020-02-21 23:50:57 +00:00
$new-reg-var-def:end:
2019-11-28 00:50:23 +00:00
# . restore registers
2020-05-04 02:26:20 +00:00
58/pop-to-eax
2019-11-28 00:50:23 +00:00
# . 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)
2019-11-29 09:24:03 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
2019-11-29 09:24:03 +00:00
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
2019-11-29 09:24:03 +00:00
# otherwise append
# var curr/eax: (addr stmt-var) = lookup(vars)
(lookup *(ebp+0x14) *(ebp+0x18)) # => eax
2019-11-29 09:24:03 +00:00
# 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
#
2019-11-29 09:24:03 +00:00
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:
2019-11-29 09:24:03 +00:00
# . restore registers
5f/pop-to-edi
2019-11-29 09:24:03 +00:00
59/pop-to-ecx
58/pop-to-eax
2019-11-29 09:24:03 +00:00
# . 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
2020-05-06 21:59:12 +00:00
50/push-eax
56/push-esi
# var container-type/esi: type-id
(container-type *(ebp+8)) # => eax
89/<- %esi 0/r32/eax
2020-05-06 21:59:12 +00:00
# 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)
2020-05-24 07:51:52 +00:00
#? (write-buffered Stderr "constant: ")
#? (write-slice-buffered Stderr *(ebp+0xc))
#? (write-buffered Stderr Newline)
#? (flush Stderr)
2020-05-06 21:59:12 +00:00
(find-or-create-typeinfo-output-var %eax *(ebp+0xc) *(ebp+0x10))
2020-05-24 07:51:52 +00:00
#? 8b/-> *(ebp+0x10) 0/r32/eax
#? (write-buffered Stderr "@")
#? (lookup *eax *(eax+4))
#? (print-int32-buffered Stderr %eax)
#? (lookup *eax *(eax+4))
#? (write-buffered Stderr %eax)
#? (write-buffered Stderr Newline)
#? (flush Stderr)
#? (write-buffered Stderr "offset: ")
#? 8b/-> *(eax+0x14) 0/r32/eax
#? (print-int32-buffered Stderr %eax)
#? (write-buffered Stderr Newline)
#? (flush Stderr)
$lookup-or-create-constant:end:
2020-05-06 21:59:12 +00:00
# . reclaim locals
81 0/subop/add %esp 8/imm32
# . restore registers
5e/pop-to-esi
2020-05-06 21:59:12 +00:00
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
2020-03-10 23:39:06 +00:00
# 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
2020-05-22 21:43:26 +00:00
(lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax
(lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax
2020-03-10 23:39:06 +00:00
{
2020-04-12 09:33:01 +00:00
81 7/subop/compare *(eax+8) 0/imm32 # Tree-right
2020-03-10 23:39:06 +00:00
74/jump-if-= break/disp8
2020-05-22 21:43:26 +00:00
(lookup *(eax+0xc) *(eax+0x10)) # Tree-right Tree-right => eax
(lookup *(eax+4) *(eax+8)) # Tree-left Tree-left => eax
2020-03-10 23:39:06 +00:00
}
2020-04-12 09:33:01 +00:00
8b/-> *(eax+4) 0/r32/eax # Tree-value
$container-type:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
2020-04-23 00:13:59 +00:00
find-or-create-typeinfo: # t: type-id, out: (addr handle typeinfo)
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
2020-04-23 00:13:59 +00:00
50/push-eax
51/push-ecx
2020-04-23 00:13:59 +00:00
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)
{
2020-04-23 00:13:59 +00:00
# if (*out != 0) break
81 7/subop/compare *edi 0/imm32
0f 85/jump-if-!= break/disp32
$find-or-create-typeinfo:create:
2020-04-23 00:13:59 +00:00
# *out = allocate
(allocate Heap *Typeinfo-size %edi)
# var tmp/eax: (addr typeinfo) = lookup(*out)
(lookup *edi *(edi+4)) # => eax
2020-05-22 21:43:26 +00:00
#? (write-buffered Stderr "created typeinfo at ")
#? (print-int32-buffered Stderr %eax)
#? (write-buffered Stderr " for type-id ")
#? (print-int32-buffered Stderr *(ebp+8))
#? (write-buffered Stderr Newline)
#? (flush Stderr)
2020-04-23 00:13:59 +00:00
# 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
2020-04-23 00:13:59 +00:00
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:
2020-05-22 21:43:26 +00:00
# . reclaim locals
81 0/subop/add %esp 8/imm32
# . restore registers
2020-04-23 00:13:59 +00:00
5f/pop-to-edi
5a/pop-to-edx
59/pop-to-ecx
2020-04-23 00:13:59 +00:00
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
2020-04-23 00:13:59 +00:00
find-typeinfo: # t: type-id, out: (addr handle typeinfo)
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
2020-04-23 00:13:59 +00:00
50/push-eax
51/push-ecx
2020-04-23 00:13:59 +00:00
52/push-edx
57/push-edi
# ecx = t
8b/-> *(ebp+8) 1/r32/ecx
2020-04-23 00:13:59 +00:00
# edi = out
8b/-> *(ebp+0xc) 7/r32/edi
# *out = Program->types
8b/-> *_Program-types 0/r32/eax
2020-04-23 00:13:59 +00:00
89/<- *edi 0/r32/eax
8b/-> *_Program-types->payload 0/r32/eax
89/<- *(edi+4) 0/r32/eax
{
2020-04-23 00:13:59 +00:00
# if (*out == 0) break
81 7/subop/compare *edi 0/imm32
74/jump-if-= break/disp8
2020-05-04 02:14:49 +00:00
# var tmp/eax: (addr typeinfo) = lookup(*out)
2020-04-23 00:13:59 +00:00
(lookup *edi *(edi+4)) # => eax
# if (tmp->id == t) break
39/compare *eax 1/r32/ecx # Typeinfo-id
2020-04-23 00:13:59 +00:00
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
2020-04-23 00:13:59 +00:00
5f/pop-to-edi
5a/pop-to-edx
59/pop-to-ecx
2020-04-23 00:13:59 +00:00
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
2020-04-23 23:22:41 +00:00
50/push-eax
52/push-edx
57/push-edi
2020-05-24 07:51:52 +00:00
# var dest/edi: (handle typeinfo-entry)
2020-04-23 23:22:41 +00:00
68/push 0/imm32
68/push 0/imm32
2020-04-23 23:38:55 +00:00
89/<- %edi 4/r32/esp
2020-05-24 07:51:52 +00:00
# find-or-create-typeinfo-fields(T, f, dest)
2020-04-23 23:38:55 +00:00
(find-or-create-typeinfo-fields *(ebp+8) *(ebp+0xc) %edi)
2020-05-24 07:51:52 +00:00
# var dest-addr/edi: (addr typeinfo-entry) = lookup(dest)
2020-04-23 23:38:55 +00:00
(lookup *edi *(edi+4)) # => eax
89/<- %edi 0/r32/eax
2020-05-24 07:51:52 +00:00
# if dest-addr->output-var doesn't exist, create it
{
2020-05-24 07:51:52 +00:00
81 7/subop/compare *(edi+0xc) 0/imm32 # Typeinfo-entry-output-var
0f 85/jump-if-!= break/disp32
2020-05-24 07:51:52 +00:00
# dest-addr->output-var = new var(dummy name, type, -1 offset)
2020-04-24 01:38:37 +00:00
# . 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
2020-05-24 07:51:52 +00:00
8d/copy-address *(edi+0xc) 2/r32/edx
(new-var Heap *eax *(eax+4) %edx)
2020-04-24 01:38:37 +00:00
# . reclaim name
81 0/subop/add %esp 8/imm32
2020-05-24 07:51:52 +00:00
# var result/edx: (addr var) = lookup(dest-addr->output-var)
(lookup *(edi+0xc) *(edi+0x10)) # => eax
2020-04-23 23:38:55 +00:00
89/<- %edx 0/r32/eax
2020-05-24 07:51:52 +00:00
# result->type = new constant type
2020-04-24 01:38:37 +00:00
8d/copy-address *(edx+8) 0/r32/eax # Var-type
2020-04-23 23:47:46 +00:00
(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
2020-05-24 07:51:52 +00:00
# result->offset isn't filled out yet
2020-04-23 23:38:55 +00:00
c7 0/subop/copy *(edx+0x14) -1/imm32/uninitialized # Var-offset
}
2020-05-24 07:51:52 +00:00
# out = dest-addr->output-var
8b/-> *(ebp+0x10) 2/r32/edx
8b/-> *(edi+0xc) 0/r32/eax # Typeinfo-entry-output-var
89/<- *edx 0/r32/eax
8b/-> *(edi+0x10) 0/r32/eax # Typeinfo-entry-output-var
89/<- *(edx+4) 0/r32/eax
$find-or-create-typeinfo-output-var:end:
2020-04-23 23:22:41 +00:00
# . reclaim locals
81 0/subop/add %esp 8/imm32
# . restore registers
2020-04-23 23:22:41 +00:00
5f/pop-to-edi
5a/pop-to-edx
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
2020-04-23 23:22:41 +00:00
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
2020-04-23 23:22:41 +00:00
50/push-eax
56/push-esi
2020-04-23 23:22:41 +00:00
57/push-edi
2020-05-22 21:43:26 +00:00
# eax = lookup(T->fields)
8b/-> *(ebp+8) 0/r32/eax
(lookup *(eax+4) *(eax+8)) # Typeinfo-fields Typeinfo-fields => eax
# edi = out
8b/-> *(ebp+0x10) 7/r32/edi
2020-04-23 23:22:41 +00:00
# var src/esi: (addr handle typeinfo-entry) = get-or-insert-slice(T->fields, f)
2020-05-22 21:43:26 +00:00
(get-or-insert-slice %eax *(ebp+0xc) *Typeinfo-fields-row-size Heap) # => eax
89/<- %esi 0/r32/eax
2020-04-23 23:22:41 +00:00
# if src doesn't exist, allocate it
{
2020-04-23 23:22:41 +00:00
81 7/subop/compare *esi 0/imm32
2020-05-22 22:56:38 +00:00
75/jump-if-!= break/disp8
2020-05-22 21:43:26 +00:00
(allocate Heap *Typeinfo-entry-size %esi)
#? (write-buffered Stderr "handle at ")
#? (print-int32-buffered Stderr %esi)
#? (write-buffered Stderr ": ")
#? (print-int32-buffered Stderr *esi)
#? (write-buffered Stderr " ")
#? (print-int32-buffered Stderr *(esi+4))
#? (write-buffered Stderr Newline)
#? (flush Stderr)
#? (lookup *esi *(esi+4))
#? (write-buffered Stderr "created typeinfo fields at ")
#? (print-int32-buffered Stderr %esi)
#? (write-buffered Stderr " for ")
#? (print-int32-buffered Stderr *(ebp+8))
#? (write-buffered Stderr Newline)
#? (flush Stderr)
}
2020-05-22 21:43:26 +00:00
# *out = src
# . *edi = *src
8b/-> *esi 0/r32/eax
2020-04-23 23:22:41 +00:00
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
2020-04-23 23:22:41 +00:00
5f/pop-to-edi
5e/pop-to-esi
2020-04-23 23:22:41 +00:00
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
2020-04-24 00:24:17 +00:00
populate-mu-type: # in: (addr stream byte), t: (addr typeinfo)
# pseudocode:
# var line: (stream byte 512)
2020-03-08 23:30:07 +00:00
# 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
2020-03-08 23:30:07 +00:00
# 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
2020-05-22 21:43:26 +00:00
# var v/esi: (handle var)
68/push 0/imm32
68/push 0/imm32
89/<- %esi 4/r32/esp
# var r/ebx: (handle typeinfo-entry)
68/push 0/imm32
68/push 0/imm32
89/<- %ebx 4/r32/esp
{
$populate-mu-type:line-loop:
(clear-stream %ecx)
(read-line-buffered *(ebp+8) %ecx)
# if (line->write == 0) abort
81 7/subop/compare *ecx 0/imm32
0f 84/jump-if-= $populate-mu-type: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
2020-03-08 23:02:32 +00:00
(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:
2020-05-22 21:43:26 +00:00
# v = parse-var-with-type(word-slice, first-line)
# must do this first to strip the trailing ':' from word-slice before
# using it in find-or-create-typeinfo-fields below
# TODO: clean up that mutation in parse-var-with-type
(parse-var-with-type %edx %ecx %esi) # => eax
# var tmp/ecx
51/push-ecx
$populate-mu-type:create-typeinfo-fields:
# var r/ebx: (handle typeinfo-entry)
2020-05-22 21:43:26 +00:00
(find-or-create-typeinfo-fields %edi %edx %ebx)
# r->index = curr-index
2020-05-22 21:43:26 +00:00
(lookup *ebx *(ebx+4)) # => eax
8b/-> *(ebp-4) 1/r32/ecx
2020-05-22 22:56:38 +00:00
#? (write-buffered Stderr "saving index ")
#? (print-int32-buffered Stderr %ecx)
#? (write-buffered Stderr " at ")
#? (print-int32-buffered Stderr %edi)
#? (write-buffered Stderr Newline)
#? (flush Stderr)
2020-05-22 21:43:26 +00:00
89/<- *(eax+8) 1/r32/ecx # Typeinfo-entry-index
# ++curr-index
ff 0/subop/increment *(ebp-4)
$populate-mu-type:set-input-type:
# r->input-var = v
2020-05-22 21:43:26 +00:00
8b/-> *esi 1/r32/ecx
89/<- *eax 1/r32/ecx # Typeinfo-entry-input-var
8b/-> *(esi+4) 1/r32/ecx
89/<- *(eax+4) 1/r32/ecx # Typeinfo-entry-input-var
59/pop-to-ecx
{
$populate-mu-type:create-output-type:
# if (r->output-var == 0) create a new var with some placeholder data
2020-05-22 22:56:38 +00:00
81 7/subop/compare *(eax+0xc) 0/imm32 # Typeinfo-entry-output-var
75/jump-if-!= break/disp8
2020-05-22 22:56:38 +00:00
8d/copy-address *(eax+0xc) 0/r32/eax # Typeinfo-entry-output-var
2020-05-22 21:43:26 +00:00
(new-literal Heap %edx %eax)
}
e9/jump loop/disp32
}
$populate-mu-type:invalidate-total-size-in-bytes:
# Offsets and total size may not be accurate here since we may not yet
# have encountered the element types.
# We'll recompute them separately after parsing the entire program.
2020-05-22 21:43:26 +00:00
c7 0/subop/copy *(edi+0xc) -2/imm32/uninitialized # Typeinfo-total-size-in-bytes
$populate-mu-type:end:
# . reclaim locals
2020-05-22 21:43:26 +00:00
81 0/subop/add %esp 0x224/imm32
# . restore registers
5f/pop-to-edi
5e/pop-to-esi
5b/pop-to-ebx
5a/pop-to-edx
59/pop-to-ecx
58/pop-to-eax
# reclaim curr-index
81 0/subop/add %esp 4/imm32
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
$populate-mu-type: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
$populate-mu-type-sizes:total-sizes:
2020-05-22 21:43:26 +00:00
# var curr/eax: (addr typeinfo) = lookup(Program->types)
(lookup *_Program-types *_Program-types->payload) # => eax
{
# if (curr == null) break
2020-05-22 21:43:26 +00:00
3d/compare-eax-and 0/imm32/null
74/jump-if-= break/disp8
2020-05-22 21:43:26 +00:00
(populate-mu-type-sizes-in-type %eax)
# curr = lookup(curr->next)
(lookup *(eax+0x10) *(eax+0x14)) # Typeinfo-next Typeinfo-next => eax
eb/jump loop/disp8
}
$populate-mu-type-sizes:offsets:
2020-05-22 21:43:26 +00:00
# curr = *Program->types
(lookup *_Program-types *_Program-types->payload) # => eax
{
# if (curr == null) break
2020-05-22 21:43:26 +00:00
3d/compare-eax-and 0/imm32/null
74/jump-if-= break/disp8
2020-05-22 21:43:26 +00:00
(populate-mu-type-offsets %eax)
# curr = curr->next
2020-05-22 21:43:26 +00:00
(lookup *(eax+0x10) *(eax+0x14)) # Typeinfo-next Typeinfo-next => eax
eb/jump loop/disp8
}
$populate-mu-type-sizes:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
# compute sizes of all fields, recursing as necessary
# sum up all their sizes to arrive at total size
# fields may be out of order, but that doesn't affect the answer
populate-mu-type-sizes-in-type: # T: (addr typeinfo)
# . 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
2020-05-22 21:43:26 +00:00
81 7/subop/compare *(esi+0xc) 0/imm32 # Typeinfo-total-size-in-bytes
0f 8d/jump-if->= $populate-mu-type-sizes-in-type:end/disp32
# if T is being computed, abort
2020-05-22 21:43:26 +00:00
81 7/subop/compare *(esi+0xc) -1/imm32/being-computed # Typeinfo-total-size-in-bytes
0f 84/jump-if-= $populate-mu-type-sizes-in-type:abort/disp32
# tag T (-2 to -1) to avoid infinite recursion
2020-05-22 21:43:26 +00:00
c7 0/subop/copy *(esi+0xc) -1/imm32/being-computed # Typeinfo-total-size-in-bytes
# var total-size/edi: int = 0
bf/copy-to-edi 0/imm32
# - for every field, if it's a user-defined type, compute its size
2020-05-22 21:43:26 +00:00
# var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
(lookup *(esi+4) *(esi+8)) # Typeinfo-fields Typeinfo-fields => eax
89/<- %ecx 0/r32/eax
# var table-size/edx: int = table->write
8b/-> *ecx 2/r32/edx # stream-write
# var curr/ecx: (addr table_row) = table->data
8d/copy-address *(ecx+0xc) 1/r32/ecx
# var max/edx: (addr table_row) = table->data + table->write
8d/copy-address *(ecx+edx) 2/r32/edx
{
$populate-mu-type-sizes-in-type:loop:
# if (curr >= max) break
39/compare %ecx 2/r32/edx
2020-05-22 22:56:38 +00:00
73/jump-if-addr>= break/disp8
2020-05-22 21:43:26 +00:00
# var t/eax: (addr typeinfo-entry) = lookup(curr->value)
(lookup *(ecx+8) *(ecx+0xc)) # => eax
# compute size of t->input-var
(lookup *eax *(eax+4)) # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
(compute-size-of-var %eax) # => eax
# result += eax
01/add-to %edi 0/r32/eax
# curr += row-size
2020-05-22 21:43:26 +00:00
81 0/subop/add %ecx 0x10/imm32 # Typeinfo-fields-row-size
#
2020-05-22 22:56:38 +00:00
eb/jump loop/disp8
}
# - save result
2020-05-22 21:43:26 +00:00
89/<- *(esi+0xc) 7/r32/edi # Typeinfo-total-size-in-bytes
$populate-mu-type-sizes-in-type:end:
# . restore registers
5f/pop-to-edi
5e/pop-to-esi
5a/pop-to-edx
59/pop-to-ecx
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
$populate-mu-type-sizes-in-type:abort:
(write-buffered 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
2020-03-12 00:34:48 +00:00
# . push registers
51/push-ecx
2020-05-06 22:03:51 +00:00
# var t/ecx: (addr tree type-id) = lookup(v->type)
2020-03-12 00:34:48 +00:00
8b/-> *(ebp+8) 1/r32/ecx
2020-05-22 21:43:26 +00:00
(lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax
2020-05-06 22:03:51 +00:00
89/<- %ecx 0/r32/eax
2020-05-22 21:43:26 +00:00
# if (t->is-atom == false) t = lookup(t->left)
2020-03-12 00:34:48 +00:00
{
2020-04-12 09:33:01 +00:00
81 7/subop/compare *ecx 0/imm32/false # Tree-is-atom
75/jump-if-!= break/disp8
2020-05-06 22:03:51 +00:00
(lookup *(ecx+4) *(ecx+8)) # Tree-left Tree-left => eax
89/<- %ecx 0/r32/eax
2020-03-12 00:34:48 +00:00
}
2020-05-06 22:03:51 +00:00
# TODO: ensure t is an atom
(compute-size-of-type-id *(ecx+4)) # Tree-value => eax
$compute-size-of-var:end:
2020-03-12 00:34:48 +00:00
# . 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
# . save registers
51/push-ecx
# var out/ecx: (handle typeinfo)
68/push 0/imm32
68/push 0/imm32
89/<- %ecx 4/r32/esp
# eax = t
8b/-> *(ebp+8) 0/r32/eax
# if 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 %ecx)
{
81 7/subop/compare *ecx 0/imm32
74/jump-if-= break/disp8
$compute-size-of-type-id:user-defined:
(populate-mu-type-sizes %eax)
2020-05-22 21:43:26 +00:00
8b/-> *(eax+0xc) 0/r32/eax # Typeinfo-total-size-in-bytes
eb/jump $compute-size-of-type-id:end/disp8
}
# otherwise return the word size
b8/copy-to-eax 4/imm32
$compute-size-of-type-id:end:
# . reclaim locals
81 0/subop/add %esp 8/imm32
# . restore registers
59/pop-to-ecx
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
# at this point we have total sizes for all user-defined types
# compute offsets for each element
# complication: fields may be out of order
populate-mu-type-offsets: # in: (addr typeinfo)
# . 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
2020-05-22 22:56:38 +00:00
#? (dump-typeinfos "aaa\n")
# var curr-offset/edi: int = 0
bf/copy-to-edi 0/imm32
2020-05-22 22:56:38 +00:00
# var table/ecx: (addr table string_key (handle typeinfo-entry)) = lookup(in->fields)
8b/-> *(ebp+8) 1/r32/ecx
(lookup *(ecx+4) *(ecx+8)) # Typeinfo-fields Typeinfo-fields => eax
89/<- %ecx 0/r32/eax
# var num-elems/edx: int = table->write / Typeinfo-fields-row-size
8b/-> *ecx 2/r32/edx # stream-write
c1 5/subop/shift-right-logical %edx 4/imm8
# var i/ebx: int = 0
bb/copy-to-ebx 0/imm32
{
$populate-mu-type-offsets:loop:
39/compare %ebx 2/r32/edx
7d/jump-if->= break/disp8
2020-05-22 22:56:38 +00:00
#? (write-buffered Stderr "looking up index ")
#? (print-int32-buffered Stderr %ebx)
#? (write-buffered Stderr " in ")
#? (print-int32-buffered Stderr *(ebp+8))
#? (write-buffered Stderr Newline)
#? (flush Stderr)
# 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)
(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
2020-05-22 22:56:38 +00:00
#? (write-buffered Stderr "comparing ")
#? (print-int32-buffered Stderr %ebx)
#? (write-buffered Stderr " and ")
#? (print-int32-buffered Stderr *(ebp+0xc))
#? (write-buffered Stderr Newline)
#? (flush Stderr)
39/compare *(ebp+0xc) 3/r32/ebx
74/jump-if-= $locate-typeinfo-entry-with-index:end/disp8
# curr += Typeinfo-entry-size
81 0/subop/add %ecx 0x10/imm32 # Typeinfo-entry-size
#
eb/jump loop/disp8
}
# return 0
b8/copy-to-eax 0/imm32
$locate-typeinfo-entry-with-index:end:
2020-05-22 22:56:38 +00:00
#? (write-buffered Stderr "returning ")
#? (print-int32-buffered Stderr %eax)
#? (write-buffered Stderr Newline)
#? (flush Stderr)
# . restore registers
5f/pop-to-edi
5e/pop-to-esi
5b/pop-to-ebx
5a/pop-to-edx
59/pop-to-ecx
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
$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
2020-05-22 21:43:26 +00:00
dump-typeinfos: # hdr: (addr array byte)
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
#
(write-buffered Stderr *(ebp+8))
(flush Stderr)
# var curr/eax: (addr typeinfo) = lookup(Program->types)
(lookup *_Program-types *_Program-types->payload) # => eax
{
# if (curr == null) break
3d/compare-eax-and 0/imm32
74/jump-if-= break/disp8
(write-buffered Stderr "---\n")
(flush Stderr)
(dump-typeinfo %eax)
# curr = lookup(curr->next)
(lookup *(eax+0x10) *(eax+0x14)) # Typeinfo-next Typeinfo-next => eax
eb/jump loop/disp8
}
$dump-typeinfos:end:
# . restore registers
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
dump-typeinfo: # in: (addr typeinfo)
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
51/push-ecx
52/push-edx
53/push-ebx
56/push-esi
57/push-edi
# esi = in
8b/-> *(ebp+8) 6/r32/esi
# var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
(lookup *(esi+4) *(esi+8)) # Typeinfo-fields Typeinfo-fields => eax
89/<- %ecx 0/r32/eax
(write-buffered Stderr "id:")
(print-int32-buffered Stderr *esi)
(write-buffered Stderr "\n")
(write-buffered Stderr "fields @ ")
(print-int32-buffered Stderr %ecx)
(write-buffered Stderr Newline)
(flush Stderr)
(write-buffered Stderr " write: ")
(print-int32-buffered Stderr *ecx)
(write-buffered Stderr Newline)
(flush Stderr)
(write-buffered Stderr " read: ")
(print-int32-buffered Stderr *(ecx+4))
(write-buffered Stderr Newline)
(flush Stderr)
(write-buffered Stderr " size: ")
(print-int32-buffered Stderr *(ecx+8))
(write-buffered Stderr Newline)
(flush Stderr)
# var table-size/edx: int = table->write
8b/-> *ecx 2/r32/edx # stream-write
# var curr/ecx: (addr table_row) = table->data
8d/copy-address *(ecx+0xc) 1/r32/ecx
# var max/edx: (addr table_row) = table->data + table->write
8d/copy-address *(ecx+edx) 2/r32/edx
{
$dump-typeinfo:loop:
# if (curr >= max) break
39/compare %ecx 2/r32/edx
0f 83/jump-if-addr>= break/disp32
(write-buffered Stderr " row:\n")
(write-buffered Stderr " key: ")
(print-int32-buffered Stderr *ecx)
(write-buffered Stderr ",")
(print-int32-buffered Stderr *(ecx+4))
(write-buffered Stderr " = '")
(lookup *ecx *(ecx+4))
(write-buffered Stderr %eax)
(write-buffered Stderr "' @ ")
(print-int32-buffered Stderr %eax)
(write-buffered Stderr Newline)
(flush Stderr)
(write-buffered Stderr " value: ")
(print-int32-buffered Stderr *(ecx+8))
(write-buffered Stderr ",")
(print-int32-buffered Stderr *(ecx+0xc))
(write-buffered Stderr " = typeinfo-entry@")
(lookup *(ecx+8) *(ecx+0xc))
(print-int32-buffered Stderr %eax)
(write-buffered Stderr Newline)
(flush Stderr)
(write-buffered Stderr " input var@")
(print-int32-buffered Stderr *eax)
(write-buffered Stderr ",")
(print-int32-buffered Stderr *(eax+4))
(write-buffered Stderr "->")
(lookup *eax *(eax+4)) # Typeinfo-entry-input-var
(print-int32-buffered Stderr %eax)
{
3d/compare-eax-and 0/imm32
74/jump-if-= break/disp8
(write-buffered Stderr " ")
2020-05-22 22:56:38 +00:00
# TODO
2020-05-22 21:43:26 +00:00
}
(write-buffered Stderr Newline)
(flush Stderr)
(lookup *(ecx+8) *(ecx+0xc))
2020-05-22 22:56:38 +00:00
(write-buffered Stderr " index: ")
(print-int32-buffered Stderr *(eax+8))
(write-buffered Stderr Newline)
(flush Stderr)
2020-05-22 21:43:26 +00:00
(write-buffered Stderr " output var@")
(print-int32-buffered Stderr *(eax+0xc))
(write-buffered Stderr ",")
(print-int32-buffered Stderr *(eax+0x10))
(write-buffered Stderr "->")
(lookup *(eax+0xc) *(eax+0x10)) # Typeinfo-entry-output-var
(print-int32-buffered Stderr %eax)
(write-buffered Stderr Newline)
(flush Stderr)
{
3d/compare-eax-and 0/imm32
0f 84/jump-if-= break/disp32
(write-buffered Stderr " name: ")
89/<- %ebx 0/r32/eax
(print-int32-buffered Stderr *ebx) # Var-name
(write-buffered Stderr ",")
(print-int32-buffered Stderr *(ebx+4)) # Var-name
(write-buffered Stderr "->")
(lookup *ebx *(ebx+4)) # Var-name
(print-int32-buffered Stderr %eax)
{
3d/compare-eax-and 0/imm32
74/jump-if-= break/disp8
(write-buffered Stderr Space)
(write-buffered Stderr %eax)
}
(write-buffered Stderr Newline)
(flush Stderr)
(write-buffered Stderr " block depth: ")
(print-int32-buffered Stderr *(ebx+0x10)) # Var-block-depth
(write-buffered Stderr Newline)
(flush Stderr)
(write-buffered Stderr " stack offset: ")
(print-int32-buffered Stderr *(ebx+0x14)) # Var-offset
(write-buffered Stderr Newline)
(flush Stderr)
(write-buffered Stderr " reg: ")
(print-int32-buffered Stderr *(ebx+0x18)) # Var-register
(write-buffered Stderr ",")
(print-int32-buffered Stderr *(ebx+0x1c)) # Var-register
(write-buffered Stderr "->")
(flush Stderr)
(lookup *(ebx+0x18) *(ebx+0x1c)) # Var-register
(print-int32-buffered Stderr %eax)
{
3d/compare-eax-and 0/imm32
74/jump-if-= break/disp8
(write-buffered Stderr Space)
(write-buffered Stderr %eax)
}
(write-buffered Stderr Newline)
(flush Stderr)
}
(flush Stderr)
# curr += row-size
81 0/subop/add %ecx 0x10/imm32 # Typeinfo-fields-row-size
#
e9/jump loop/disp32
}
$dump-typeinfo:end:
# . restore registers
5f/pop-to-edi
5e/pop-to-esi
5b/pop-to-ebx
5a/pop-to-edx
59/pop-to-ecx
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
2019-11-28 00:50:23 +00:00
#######################################################
# Type-checking
#######################################################
check-mu-types:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
2019-11-28 00:50:23 +00:00
$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
2020-02-28 02:49:50 +00:00
# . save registers
51/push-ecx
2020-05-07 03:36:13 +00:00
# var t/ecx: (addr tree type-id) = lookup(v->type)
2020-02-28 02:49:50 +00:00
8b/-> *(ebp+8) 1/r32/ecx
#? (write-buffered Stderr "size-of ")
#? (print-int32-buffered Stderr %ecx)
#? (write-buffered Stderr Newline)
#? (write-buffered Stderr "type allocid: ")
#? (print-int32-buffered Stderr *(ecx+8))
#? (write-buffered Stderr Newline)
#? (flush Stderr)
2020-05-07 03:36:13 +00:00
(lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax
89/<- %ecx 0/r32/eax
2020-03-12 02:55:45 +00:00
# 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
}
2020-05-07 03:41:07 +00:00
# if (!t->is-atom?) t = lookup(t->left)
2020-03-12 00:25:41 +00:00
{
2020-04-12 09:33:01 +00:00
81 7/subop/compare *ecx 0/imm32/false # Tree-is-atom
75/jump-if-!= break/disp8
2020-05-07 03:36:13 +00:00
(lookup *(ecx+4) *(ecx+8)) # Tree-left Tree-left => eax
89/<- %ecx 0/r32/eax
2020-03-12 00:25:41 +00:00
}
2020-05-07 03:36:13 +00:00
# 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
2020-05-07 03:41:07 +00:00
# var t/ecx: (addr tree type-id) = lookup(v->type)
8b/-> *(ebp+8) 1/r32/ecx
2020-05-07 03:41:07 +00:00
(lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax
89/<- %ecx 0/r32/eax
# TODO: assert(t is an addr)
2020-05-07 03:41:07 +00:00
# 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
}
2020-05-07 03:41:07 +00:00
# if (!t->is-atom?) t = lookup(t->left)
{
2020-04-12 09:33:01 +00:00
81 7/subop/compare *ecx 0/imm32/false # Tree-is-atom
75/jump-if-!= break/disp8
2020-05-07 03:41:07 +00:00
(lookup *(ecx+4) *(ecx+8)) # Tree-left Tree-left => eax
89/<- %ecx 0/r32/eax
}
2020-05-07 03:41:07 +00:00
# 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
2020-03-12 02:55:45 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
51/push-ecx
2020-04-12 09:33:01 +00:00
# ecx = t
2020-03-12 02:55:45 +00:00
8b/-> *(ebp+8) 1/r32/ecx
2020-05-18 08:02:35 +00:00
# if t->is-atom?, return false
2020-04-12 09:33:01 +00:00
81 7/subop/compare *ecx 0/imm32/false # Tree-is-atom
2020-05-18 08:02:35 +00:00
75/jump-if-!= $is-mu-array?:return-false/disp8
# if !t->left->is-atom?, return false
(lookup *(ecx+4) *(ecx+8)) # Tree-left Tree-left => eax
81 7/subop/compare *eax 0/imm32/false # Tree-is-atom
74/jump-if-= $is-mu-array?:return-false/disp8
2020-04-12 09:33:01 +00:00
# return t->left->value == array
2020-05-18 08:02:35 +00:00
81 7/subop/compare *(eax+4) 3/imm32/array-type-id # Tree-value
2020-03-12 02:55:45 +00:00
0f 94/set-if-= %al
2020-05-18 08:02:35 +00:00
81 4/subop/and %eax 0xff/imm32
eb/jump $is-mu-array?:end/disp8
$is-mu-array?:return-false:
b8/copy-to-eax 0/imm32/false
2020-03-12 02:55:45 +00:00
$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
2020-03-12 02:55:45 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
51/push-ecx
52/push-edx
#
8b/-> *(ebp+8) 1/r32/ecx
# TODO: assert that a->left is 'array'
(lookup *(ecx+0xc) *(ecx+0x10)) # Tree-right Tree-right => eax
89/<- %ecx 0/r32/eax
# var elem-type/edx: type-id = a->right->left->value
(lookup *(ecx+4) *(ecx+8)) # Tree-left Tree-left => eax
8b/-> *(eax+4) 2/r32/edx # Tree-value
2020-03-12 02:55:45 +00:00
# var array-size/ecx: int = a->right->right->left->value
(lookup *(ecx+0xc) *(ecx+0x10)) # Tree-right Tree-right => eax
(lookup *(eax+4) *(eax+8)) # Tree-left Tree-left => eax
8b/-> *(eax+4) 1/r32/ecx # Tree-value
2020-03-12 02:55:45 +00:00
# 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
2020-03-12 02:55:45 +00:00
$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
# . save registers
51/push-ecx
# var out/ecx: (handle typeinfo)
68/push 0/imm32
68/push 0/imm32
89/<- %ecx 4/r32/esp
# eax = t
8b/-> *(ebp+8) 0/r32/eax
# if 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
2020-02-28 02:49:50 +00:00
# if v has a user-defined type, return its size
# TODO: support non-atom type
(find-typeinfo %eax %ecx)
2020-02-28 02:49:50 +00:00
{
81 7/subop/compare *ecx 0/imm32
2020-02-28 02:49:50 +00:00
74/jump-if-= break/disp8
2020-03-09 01:11:19 +00:00
$size-of-type-id:user-defined:
2020-05-22 22:56:38 +00:00
(lookup *ecx *(ecx+4)) # => eax
2020-05-21 07:23:55 +00:00
8b/-> *(eax+0xc) 0/r32/eax # Typeinfo-total-size-in-bytes
eb/jump $size-of-type-id:end/disp8
2020-02-28 02:49:50 +00:00
}
# otherwise return the word size
b8/copy-to-eax 4/imm32
2020-03-09 01:11:19 +00:00
$size-of-type-id:end:
# . reclaim locals
81 0/subop/add %esp 8/imm32
# . restore registers
59/pop-to-ecx
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
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
2020-04-12 09:33:01 +00:00
(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)
2020-04-12 09:33:01 +00:00
(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
2019-11-28 00:50:23 +00:00
#######################################################
# Code-generation
#######################################################
== data
Curr-block-depth: # (addr int)
0/imm32
Curr-local-stack-offset: # (addr int)
0/imm32
== code
2020-01-27 08:36:44 +00:00
emit-subx: # out: (addr buffered-file)
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
2020-05-18 00:59:12 +00:00
# var curr/eax: (addr function) = *Program->functions
(lookup *_Program-functions *_Program-functions->payload) # => eax
{
# if (curr == null) break
2020-05-18 00:59:12 +00:00
3d/compare-eax-and 0/imm32
0f 84/jump-if-= break/disp32
2020-05-18 00:59:12 +00:00
(emit-subx-function *(ebp+8) %eax)
# curr = lookup(curr->next)
(lookup *(eax+0x20) *(eax+0x24)) # Function-next Function-next => eax
e9/jump loop/disp32
}
$emit-subx:end:
# . restore registers
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
emit-subx-function: # out: (addr buffered-file), f: (addr function)
2019-11-09 01:31:11 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# some preprocessing
(populate-mu-type-offsets-in-inouts *(ebp+0xc))
2019-11-09 01:31:11 +00:00
# . save registers
50/push-eax
51/push-ecx
2020-01-27 10:07:00 +00:00
52/push-edx
2019-11-09 01:31:11 +00:00
57/push-edi
# edi = out
8b/-> *(ebp+8) 7/r32/edi
# ecx = f
8b/-> *(ebp+0xc) 1/r32/ecx
2020-01-27 10:07:00 +00:00
# var vars/edx: (stack (addr var) 256)
2020-04-24 00:31:28 +00:00
81 5/subop/subtract %esp 0x800/imm32
68/push 0x800/imm32/size
2020-01-27 10:07:00 +00:00
68/push 0/imm32/top
89/<- %edx 4/r32/esp
2019-11-09 01:31:11 +00:00
#
2020-05-18 00:59:12 +00:00
(lookup *ecx *(ecx+4)) # Function-name Function-name => eax
(write-buffered %edi %eax)
2019-11-09 01:31:11 +00:00
(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
#
2019-11-09 01:31:11 +00:00
(emit-subx-prologue %edi)
2020-05-18 00:59:12 +00:00
(lookup *(ecx+0x18) *(ecx+0x1c)) # Function-body Function-body => eax
(emit-subx-block %edi %eax %edx)
2019-11-09 01:31:11 +00:00
(emit-subx-epilogue %edi)
# TODO: validate that *Curr-block-depth and *Curr-local-stack-offset have
# been cleaned up
2019-11-09 01:31:11 +00:00
$emit-subx-function:end:
2020-01-27 10:07:00 +00:00
# . reclaim locals
2020-05-18 00:59:12 +00:00
81 0/subop/add %esp 808/imm32
2019-11-09 01:31:11 +00:00
# . restore registers
5f/pop-to-edi
2020-01-27 10:07:00 +00:00
5a/pop-to-edx
2019-11-09 01:31:11 +00:00
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
2020-05-18 00:59:12 +00:00
# var curr/ecx: (addr list var) = lookup(f->inouts)
8b/-> *(ebp+8) 1/r32/ecx
2020-05-18 00:59:12 +00:00
(lookup *(ecx+8) *(ecx+0xc)) # Function-inouts Function-inouts => eax
89/<- %ecx 0/r32/eax
{
$populate-mu-type-offsets-in-inouts:loop:
81 7/subop/compare %ecx 0/imm32
74/jump-if-= break/disp8
2020-05-18 00:59:12 +00:00
# var v/ebx: (addr var) = lookup(curr->value)
(lookup *ecx *(ecx+4)) # List-value List-value => eax
89/<- %ebx 0/r32/eax
2020-05-24 07:51:52 +00:00
#? (lookup *ebx *(ebx+4))
#? (write-buffered Stderr "setting offset of fn inout ")
#? (write-buffered Stderr %eax)
#? (write-buffered Stderr "@")
#? (print-int32-buffered Stderr %ebx)
#? (write-buffered Stderr " to ")
#? (print-int32-buffered Stderr %edx)
#? (write-buffered Stderr Newline)
#? (flush Stderr)
# v->offset = next-offset
2020-05-18 01:36:35 +00:00
89/<- *(ebx+0x14) 2/r32/edx # Var-offset
# next-offset += size-of(v)
(size-of %ebx) # => eax
01/add-to %edx 0/r32/eax
2020-05-18 00:59:12 +00:00
# curr = lookup(curr->next)
(lookup *(ecx+8) *(ecx+0xc)) # List-next List-next => eax
2020-05-18 01:36:35 +00:00
89/<- %ecx 0/r32/eax
2020-05-18 00:59:12 +00:00
#
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
2020-05-18 02:34:30 +00:00
# var curr-stmt/ecx: (addr stmt) = lookup(stmts->value)
(lookup *esi *(esi+4)) # List-value List-value => eax
89/<- %ecx 0/r32/eax
{
$emit-subx-stmt-list:check-for-block:
81 7/subop/compare *ecx 0/imm32/block # Stmt-tag
2020-02-07 00:32:42 +00:00
75/jump-if-!= break/disp8
$emit-subx-stmt-list:block:
(emit-subx-block *(ebp+8) %ecx *(ebp+0x10))
2020-02-07 00:32:42 +00:00
}
{
$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
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
0f 84/jump-if-= break/disp32
$emit-subx-stmt-list:branch-stmt:
2020-02-07 08:11:02 +00:00
# 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
2020-05-21 05:33:43 +00:00
(lookup *(ecx+4) *(ecx+8)) # Stmt1-operation Stmt1-operation => eax
(string-equal? %eax "loop") # => eax
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
0f 84/jump-if-= break/disp32
$emit-subx-stmt-list:unconditional-loop:
2020-05-21 05:33:43 +00:00
81 7/subop/compare *(ecx+0xc) 0/imm32 # Stmt1-inouts
# simple unconditional loops without a target
{
0f 85/jump-if-!= break/disp32
$emit-subx-stmt-list:zero-arg-unconditional-loop:
(emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth)
(emit-indent *(ebp+8) *Curr-block-depth)
(write-buffered *(ebp+8) "e9/jump loop/disp32")
(write-buffered *(ebp+8) Newline)
2020-05-18 18:22:13 +00:00
e9/jump $emit-subx-stmt-list:clean-up/disp32 # skip remaining statements; they're dead code
}
# unconditional loops with a target
{
0f 84/jump-if-= break/disp32
(emit-subx-cleanup-and-unconditional-nonlocal-branch *(ebp+8) %ecx *(ebp+0x10))
2020-05-18 18:22:13 +00:00
e9/jump $emit-subx-stmt-list:clean-up/disp32
}
}
# }}}
# unconditional breaks {{{
{
# if (!string-equal?(curr-stmt->operation, "break")) break
2020-05-21 05:33:43 +00:00
(lookup *(ecx+4) *(ecx+8)) # Stmt1-operation Stmt1-operation => eax
(string-equal? %eax "break") # => eax
3d/compare-eax-and 0/imm32/false
0f 84/jump-if-= break/disp32
$emit-subx-stmt-list:unconditional-break:
2020-05-21 05:33:43 +00:00
81 7/subop/compare *(ecx+0xc) 0/imm32 # Stmt1-inouts
# simple unconditional breaks without a target
0f 84/jump-if-= $emit-subx-stmt-list:emit-cleanup/disp32 # easy: just skip remaining statements
# unconditional breaks with a target
(emit-subx-cleanup-and-unconditional-nonlocal-branch *(ebp+8) %ecx *(ebp+0x10))
2020-05-18 18:22:13 +00:00
e9/jump $emit-subx-stmt-list:clean-up/disp32
}
# }}}
# simple conditional branches without a target {{{
2020-05-21 05:33:43 +00:00
81 7/subop/compare *(ecx+0xc) 0/imm32 # Stmt1-inouts
2020-02-07 08:11:02 +00:00
{
0f 85/jump-if-!= break/disp32
$emit-subx-stmt-list:zero-arg-conditional-branch:
2020-05-21 05:33:43 +00:00
# var old-block-depth/ebx: int = Curr-block-depth - 1
8b/-> *Curr-block-depth 3/r32/ebx
# cleanup prologue
(emit-indent *(ebp+8) *Curr-block-depth)
(write-buffered *(ebp+8) "{\n")
ff 0/subop/increment *Curr-block-depth
#
(emit-reverse-break *(ebp+8) %ecx)
# clean up until old block depth
(emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) %ebx)
# var target-block-depth/ebx: int = Curr-block-depth - 1
4b/decrement-ebx
# emit jump to target block
2020-05-21 05:33:43 +00:00
(lookup *(ecx+4) *(ecx+8)) # Stmt1-operation Stmt1-operation => eax
(string-starts-with? %eax "break") # => eax
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
{
74/jump-if-= break/disp8
(emit-unconditional-jump-to-depth *(ebp+8) *(ebp+0x10) %ebx "break")
}
2020-02-17 23:26:49 +00:00
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")
2020-02-07 08:11:02 +00:00
# continue
e9/jump $emit-subx-stmt-list:continue/disp32
}
2020-02-10 00:27:16 +00:00
# }}}
# conditional branches with an explicit target {{{
2020-02-07 08:11:02 +00:00
{
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")
2020-02-07 08:11:02 +00:00
# continue
e9/jump $emit-subx-stmt-list:continue/disp32
}
2020-02-10 00:27:16 +00:00
# }}}
}
$emit-subx-stmt-list:1-to-1:
(emit-subx-stmt *(ebp+8) %ecx Primitives)
2020-05-18 07:43:34 +00:00
e9/jump $emit-subx-stmt-list:continue/disp32
}
{
2020-02-21 23:50:57 +00:00
$emit-subx-stmt-list:check-for-var-def:
81 7/subop/compare *ecx 2/imm32/var-def # Stmt-tag
75/jump-if-!= break/disp8
2020-02-21 23:50:57 +00:00
$emit-subx-stmt-list:var-def:
(emit-subx-var-def *(ebp+8) %ecx)
(push *(ebp+0x10) *(ecx+4)) # Vardef-var
2020-05-18 02:34:30 +00:00
(push *(ebp+0x10) *(ecx+8)) # Vardef-var
# var-seen? = true
ba/copy-to-edx 1/imm32/true
2020-05-18 07:43:34 +00:00
eb/jump $emit-subx-stmt-list:continue/disp8
}
{
2020-02-21 23:50:57 +00:00
$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
2020-02-21 23:50:57 +00:00
$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
2020-05-18 07:43:34 +00:00
eb/jump $emit-subx-stmt-list:continue/disp8
}
2020-02-07 08:11:02 +00:00
$emit-subx-stmt-list:continue:
# TODO: raise an error on unrecognized Stmt-tag
2020-05-18 02:34:30 +00:00
(lookup *(esi+8) *(esi+0xc)) # List-next List-next => eax
89/<- %esi 0/r32/eax
e9/jump loop/disp32
}
$emit-subx-stmt-list:emit-cleanup:
(emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth)
2020-05-18 18:22:13 +00:00
$emit-subx-stmt-list:clean-up:
(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))
2020-03-01 06:48:13 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
2020-05-19 06:26:40 +00:00
50/push-eax
2020-03-01 06:48:13 +00:00
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
2020-05-19 06:26:40 +00:00
# TODO: assert !sv->is-deref?
# var v/ecx: (addr var) = lookup(sv->value)
(lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax
89/<- %ecx 0/r32/eax
# v->block-depth = *Curr-block-depth
8b/-> *Curr-block-depth 0/r32/eax
89/<- *(ecx+0x10) 0/r32/eax # Var-block-depth
#? (write-buffered Stderr "var ")
#? (lookup *ecx *(ecx+4))
#? (write-buffered Stderr %eax)
#? (write-buffered Stderr " at depth ")
#? (print-int32-buffered Stderr *(ecx+0x10))
#? (write-buffered Stderr Newline)
#? (flush Stderr)
# ensure that v is in a register
81 7/subop/compare *(ecx+0x18) 0/imm32 # Var-register
0f 84/jump-if-= $push-output-and-maybe-emit-spill:abort/disp32
2020-05-19 06:26:40 +00:00
# if !already-spilled-this-block?(reg, vars) emit code to spill reg
6082 - bugfix in spilling register vars In the process I'm starting to realize that my approach to avoiding spills isn't ideal. It works for local variables but not to avoid spilling outputs. To correctly decide whether to spill to an output register or not, we really need to analyze when a variable is live. If we don't do that, we'll end up in one of two bad situations: a) Don't spill the outermost use of an output register (or just the outermost scope in a function). This is weird because it's hard to explain to the programmer why they can overwrite a local with an output above a '{' but not below. b) Disallow overwriting entirely. This is easier to communicate but quite inconvenient. It's nice to be able to use eax for some temporary purpose before overwriting it with the final result of a function. If we instead track liveness, things are convenient and also easier to explain. If a temporary is used after the output has been written that's an obvious problem: "you clobbered the output". (It seems more reasonable to disallow multiple live ranges for the output. Once an output is written it can only be shadowed in a nested block.) That's the bad news. Now for some good news: One lovely property Mu the language has at the moment is that live ranges are guaranteed to be linear segments of code. We don't need to analyze loop-carried dependences. This means that we can decide whether a variable is live purely by scanning later statements for its use. (Defining 'register use' is slightly non-trivial; primitives must somehow specify when they read their output register.) So we don't actually need to worry about a loop reading a register with one type and writing to another type at the end of an iteration. The only way that can happen is if the write at the end was to a local variable, and we're guaranteeing that local variables will be reclaimed at the end of the iteration. So, the sequence of tasks: a) compute register liveness b1) verify that all register variables used at any point in a program are always the topmost use of that register. b2) decide whether to spill/shadow, clobber or flag an error. There's still the open question of where to attach liveness state. It can't be on a var, because liveness varies by use of the var. It can't be on a statement because we may want to know the liveness of variables not referenced in a given statement. Conceptually we want a matrix of locals x stmts (flattened). But I think it's simpler than that. We just want to know liveness at the time of variable declarations. A new register variable can be in one of three states w.r.t. its previous definition: either it's shadowing it, or it can clobber it, or there's a conflict and we need to raise an error. I think we can compute this information for each variable definition by an analysis similar to existing ones, maintaining a stack of variable definitions. The major difference is that we don't pop variables when a block ends. Details to be worked out. But when we do I hope to get these pending tests passing.
2020-03-06 08:06:42 +00:00
(already-spilled-this-block? %ecx *(ebp+0x10)) # => eax
3d/compare-eax-and 0/imm32/false
2020-05-19 06:26:40 +00:00
75/jump-if-!= $push-output-and-maybe-emit-spill:push/disp8
# TODO: assert(size-of(output) == 4)
# *Curr-local-stack-offset -= 4
81 5/subop/subtract *Curr-local-stack-offset 4/imm32
2020-03-01 06:48:13 +00:00
# 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)
2020-03-01 06:48:13 +00:00
(write-buffered *(ebp+8) Newline)
2020-05-19 06:26:40 +00:00
$push-output-and-maybe-emit-spill:push:
8b/-> *(ebp+0xc) 1/r32/ecx
(lookup *(ecx+0x14) *(ecx+0x18)) # Regvardef-outputs Regvardef-outputs => eax
# push(vars, sv->value)
(push *(ebp+0x10) *eax) # Stmt-var-value
(push *(ebp+0x10) *(eax+4)) # Stmt-var-value
$push-output-and-maybe-emit-spill:end:
2020-03-01 06:48:13 +00:00
# . restore registers
59/pop-to-ecx
2020-05-19 06:26:40 +00:00
58/pop-to-eax
2020-03-01 06:48:13 +00:00
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
$push-output-and-maybe-emit-spill:abort:
2020-03-01 06:53:00 +00:00
# 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
# ecx = stmt
8b/-> *(ebp+0xc) 1/r32/ecx
2020-05-21 06:27:45 +00:00
# var target/eax: (addr array byte) = curr-stmt->inouts->value->name
(lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax
(lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax
(lookup *eax *(eax+4)) # Var-name Var-name => eax
# clean up until target block
2020-05-21 06:27:45 +00:00
(emit-cleanup-code-until-target *(ebp+8) *(ebp+0x10) %eax)
# emit jump to target block
(emit-indent *(ebp+8) *Curr-block-depth)
(write-buffered *(ebp+8) "e9/jump ")
2020-05-21 06:27:45 +00:00
(write-buffered *(ebp+8) %eax)
(lookup *(ecx+4) *(ecx+8)) # Stmt1-operation Stmt1-operation => eax
(string-starts-with? %eax "break")
3d/compare-eax-and 0/imm32/false
{
74/jump-if-= break/disp8
(write-buffered *(ebp+8) ":break/disp32\n")
}
3d/compare-eax-and 0/imm32/false # just in case the function call modified flags
{
75/jump-if-!= break/disp8
(write-buffered *(ebp+8) ":loop/disp32\n")
}
$emit-subx-cleanup-and-unconditional-nonlocal-branch:end:
# . restore registers
59/pop-to-ecx
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
is-mu-branch?: # stmt: (addr stmt1) -> result/eax: boolean
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
51/push-ecx
2020-05-18 02:34:30 +00:00
# ecx = lookup(stmt->operation)
8b/-> *(ebp+8) 1/r32/ecx
2020-05-18 02:34:30 +00:00
(lookup *(ecx+4) *(ecx+8)) # Stmt1-operation Stmt1-operation => eax
89/<- %ecx 0/r32/eax
# if (stmt->operation starts with "loop") return true
2020-05-18 02:34:30 +00:00
(string-starts-with? %ecx "loop") # => eax
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
75/jump-if-not-equal $is-mu-branch?:end/disp8
# otherwise return (stmt->operation starts with "break")
2020-05-18 02:34:30 +00:00
(string-starts-with? %ecx "break") # => eax
$is-mu-branch?:end:
# . restore registers
59/pop-to-ecx
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
emit-reverse-break: # out: (addr buffered-file), stmt: (addr stmt1)
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
# eax = stmt
8b/-> *(ebp+0xc) 0/r32/eax
#
2020-05-21 05:33:43 +00:00
(lookup *(eax+4) *(eax+8)) # Stmt1-operation Stmt1-operation => eax
(get Reverse-branch %eax 0x10 "reverse-branch: ") # => eax: (addr handle array byte)
(emit-indent *(ebp+8) *Curr-block-depth)
2020-05-21 05:33:43 +00:00
(lookup *eax *(eax+4)) # => eax
(write-buffered *(ebp+8) %eax)
(write-buffered *(ebp+8) " break/disp32\n")
$emit-reverse-break:end:
# . restore registers
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
== data
2020-05-21 05:33:43 +00:00
# Table from Mu branch instructions to the reverse SubX opcodes for them.
Reverse-branch: # (table (handle array byte) (handle array byte))
# a table is a stream
2020-05-21 05:57:42 +00:00
0x140/imm32/write
0/imm32/read
2020-05-21 05:57:42 +00:00
0x140/imm32/size
# data
0x11/imm32/alloc-id _string-break-if-=/imm32 0x11/imm32/alloc-id _string_0f_85_jump_label/imm32
0x11/imm32/alloc-id _string-loop-if-=/imm32 0x11/imm32/alloc-id _string_0f_85_jump_label/imm32
0x11/imm32/alloc-id _string-break-if-!=/imm32 0x11/imm32/alloc-id _string_0f_84_jump_label/imm32
0x11/imm32/alloc-id _string-loop-if-!=/imm32 0x11/imm32/alloc-id _string_0f_84_jump_label/imm32
0x11/imm32/alloc-id _string-break-if-</imm32 0x11/imm32/alloc-id _string_0f_8d_jump_label/imm32
0x11/imm32/alloc-id _string-loop-if-</imm32 0x11/imm32/alloc-id _string_0f_8d_jump_label/imm32
0x11/imm32/alloc-id _string-break-if->/imm32 0x11/imm32/alloc-id _string_0f_8e_jump_label/imm32
0x11/imm32/alloc-id _string-loop-if->/imm32 0x11/imm32/alloc-id _string_0f_8e_jump_label/imm32
0x11/imm32/alloc-id _string-break-if-<=/imm32 0x11/imm32/alloc-id _string_0f_87_jump_label/imm32
0x11/imm32/alloc-id _string-loop-if-<=/imm32 0x11/imm32/alloc-id _string_0f_87_jump_label/imm32
0x11/imm32/alloc-id _string-break-if->=/imm32 0x11/imm32/alloc-id _string_0f_8c_jump_label/imm32
0x11/imm32/alloc-id _string-loop-if->=/imm32 0x11/imm32/alloc-id _string_0f_8c_jump_label/imm32
0x11/imm32/alloc-id _string-break-if-addr</imm32 0x11/imm32/alloc-id _string_0f_83_jump_label/imm32
0x11/imm32/alloc-id _string-loop-if-addr</imm32 0x11/imm32/alloc-id _string_0f_83_jump_label/imm32
0x11/imm32/alloc-id _string-break-if-addr>/imm32 0x11/imm32/alloc-id _string_0f_86_jump_label/imm32
0x11/imm32/alloc-id _string-loop-if-addr>/imm32 0x11/imm32/alloc-id _string_0f_86_jump_label/imm32
0x11/imm32/alloc-id _string-break-if-addr<=/imm32 0x11/imm32/alloc-id _string_0f_87_jump_label/imm32
0x11/imm32/alloc-id _string-loop-if-addr<=/imm32 0x11/imm32/alloc-id _string_0f_87_jump_label/imm32
0x11/imm32/alloc-id _string-break-if-addr>=/imm32 0x11/imm32/alloc-id _string_0f_82_jump_label/imm32
0x11/imm32/alloc-id _string-loop-if-addr>=/imm32 0x11/imm32/alloc-id _string_0f_82_jump_label/imm32
== 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
2020-05-21 05:33:43 +00:00
56/push-esi
# ecx = vars
8b/-> *(ebp+0xc) 1/r32/ecx
# var eax: int = vars->top
8b/-> *ecx 0/r32/eax
2020-05-21 05:33:43 +00:00
# var curr/esi: (addr handle var) = &vars->data[vars->top - 8]
8d/copy-address *(ecx+eax) 6/r32/esi # vars + 8 + vars->top - 8
2020-04-24 01:56:08 +00:00
# var min/ecx: (addr handle var) = vars->data
81 0/subop/add %ecx 8/imm32
# edx = depth
8b/-> *(ebp+0x10) 2/r32/edx
{
$emit-unconditional-jump-to-depth:loop:
# if (curr < min) break
2020-05-21 05:33:43 +00:00
39/compare %esi 1/r32/ecx
0f 82/jump-if-addr< break/disp32
2020-05-21 05:33:43 +00:00
# var v/ebx: (addr var) = lookup(*curr)
(lookup *esi *(esi+4)) # => eax
89/<- %ebx 0/r32/eax
# if (v->block-depth < until-block-depth) break
2020-05-21 05:33:43 +00:00
39/compare *(ebx+0x10) 2/r32/edx # Var-block-depth
0f 8c/jump-if-< break/disp32
{
$emit-unconditional-jump-to-depth:check:
# if v->block-depth != until-block-depth, continue
2020-05-21 05:33:43 +00:00
39/compare *(ebx+0x10) 2/r32/edx # Var-block-depth
0f 85/jump-if-!= break/disp32
$emit-unconditional-jump-to-depth:depth-found:
# if v is not a literal, continue
(size-of %ebx) # => eax
3d/compare-eax-and 0/imm32
0f 85/jump-if-!= break/disp32
$emit-unconditional-jump-to-depth:label-found:
# emit unconditional jump, then return
(emit-indent *(ebp+8) *Curr-block-depth)
(write-buffered *(ebp+8) "e9/jump ")
2020-05-21 05:33:43 +00:00
(lookup *ebx *(ebx+4)) # Var-name Var-name => eax
(write-buffered *(ebp+8) %eax)
(write-buffered *(ebp+8) ":")
(write-buffered *(ebp+8) *(ebp+0x14))
(write-buffered *(ebp+8) "/disp32\n")
eb/jump $emit-unconditional-jump-to-depth:end/disp8
}
2020-05-21 05:33:43 +00:00
# curr -= 8
81 5/subop/subtract %esi 8/imm32
e9/jump loop/disp32
}
# TODO: error if no label at 'depth' was found
$emit-unconditional-jump-to-depth:end:
# . restore registers
2020-05-21 05:33:43 +00:00
5e/pop-to-esi
5b/pop-to-ebx
5a/pop-to-edx
59/pop-to-ecx
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
# emit clean-up code for 'vars' until some block depth
# doesn't actually modify 'vars' so we need traverse manually inside the stack
emit-cleanup-code-until-depth: # out: (addr buffered-file), vars: (addr stack (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
2020-05-18 07:54:53 +00:00
56/push-esi
#? (write-buffered Stderr "--- cleanup\n")
#? (flush Stderr)
# ecx = vars
8b/-> *(ebp+0xc) 1/r32/ecx
2020-05-18 07:54:53 +00:00
# var esi: int = vars->top
8b/-> *ecx 6/r32/esi
2020-05-21 06:20:56 +00:00
# var curr/esi: (addr handle var) = &vars->data[vars->top - 8]
8d/copy-address *(ecx+esi) 6/r32/esi # vars + 8 + vars->top - 8
2020-04-24 01:56:08 +00:00
# var min/ecx: (addr handle var) = vars->data
81 0/subop/add %ecx 8/imm32
# edx = until-block-depth
8b/-> *(ebp+0x10) 2/r32/edx
{
$emit-cleanup-code-until-depth:loop:
# if (curr < min) break
2020-05-18 07:54:53 +00:00
39/compare %esi 1/r32/ecx
0f 82/jump-if-addr< break/disp32
2020-05-18 07:54:53 +00:00
# var v/ebx: (addr var) = lookup(*curr)
(lookup *esi *(esi+4)) # => eax
89/<- %ebx 0/r32/eax
#? (lookup *ebx *(ebx+4)) # Var-name
#? (write-buffered Stderr "var ")
#? (write-buffered Stderr %eax)
#? (write-buffered Stderr Newline)
#? (flush Stderr)
# if (v->block-depth < until-block-depth) break
2020-05-18 07:54:53 +00:00
39/compare *(ebx+0x10) 2/r32/edx # Var-block-depth
0f 8c/jump-if-< break/disp32
# if v is in a register
2020-05-18 07:54:53 +00:00
81 7/subop/compare *(ebx+0x18) 0/imm32 # Var-register
{
0f 84/jump-if-= break/disp32
{
$emit-cleanup-code-until-depth:check-for-previous-spill:
2020-05-19 06:26:40 +00:00
(same-register-spilled-before? %ebx *(ebp+0xc) %esi) # => 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 %")
2020-05-18 07:54:53 +00:00
(lookup *(ebx+0x18) *(ebx+0x1c)) # Var-register Var-register => eax
(write-buffered *(ebp+8) %eax)
(write-buffered *(ebp+8) Newline)
}
eb/jump $emit-cleanup-code-until-depth:continue/disp8
}
# otherwise v is on the stack
{
75/jump-if-!= break/disp8
$emit-cleanup-code-until-depth:var-on-stack:
(size-of %ebx) # => eax
# don't emit code for labels
3d/compare-eax-and 0/imm32
74/jump-if-= break/disp8
$emit-cleanup-code-until-depth:reclaim-var-on-stack:
(emit-indent *(ebp+8) *Curr-block-depth)
(write-buffered *(ebp+8) "81 0/subop/add %esp ")
(print-int32-buffered *(ebp+8) %eax)
(write-buffered *(ebp+8) "/imm32\n")
}
$emit-cleanup-code-until-depth:continue:
2020-05-18 07:54:53 +00:00
# curr -= 8
81 5/subop/subtract %esi 8/imm32
e9/jump loop/disp32
}
$emit-cleanup-code-until-depth:end:
# . restore registers
2020-05-21 05:33:43 +00:00
5e/pop-to-esi
5b/pop-to-ebx
5a/pop-to-edx
59/pop-to-ecx
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
# emit clean-up code for 'vars' until 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
2020-05-21 06:20:56 +00:00
# var curr/edx: (addr handle var) = &vars->data[vars->top - 8]
8d/copy-address *(ecx+eax) 2/r32/edx # vars + 8 + vars->top - 8
2020-04-24 01:56:08 +00:00
# var min/ecx: (addr handle var) = vars->data
81 0/subop/add %ecx 8/imm32
{
$emit-cleanup-code-until-target:loop:
# if (curr < min) break
39/compare %edx 1/r32/ecx
0f 82/jump-if-addr< break/disp32
2020-05-18 07:54:53 +00:00
# var v/ebx: (handle var) = lookup(*curr)
(lookup *edx *(edx+4)) # => eax
89/<- %ebx 0/r32/eax
# if (v->name == until-block-label) break
2020-05-21 06:27:45 +00:00
(lookup *ebx *(ebx+4)) # Var-name Var-name => eax
(string-equal? %eax *(ebp+0x10)) # => eax
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
0f 85/jump-if-!= break/disp32
# if v is in a register
2020-05-21 06:27:45 +00:00
81 7/subop/compare *(ebx+0x18) 0/imm32 # Var-register
{
2020-05-21 06:27:45 +00:00
0f 84/jump-if-= break/disp32
{
$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 %")
2020-05-21 06:27:45 +00:00
(lookup *(ebx+0x18) *(ebx+0x1c)) # Var-register Var-register => eax
(write-buffered *(ebp+8) %eax)
(write-buffered *(ebp+8) Newline)
}
eb/jump $emit-cleanup-code-until-target:continue/disp8
}
# otherwise v is on the stack
{
75/jump-if-!= break/disp8
$emit-cleanup-code-until-target:reclaim-var-on-stack:
(size-of %ebx) # => eax
# don't emit code for labels
3d/compare-eax-and 0/imm32
74/jump-if-= break/disp8
#
(emit-indent *(ebp+8) *Curr-block-depth)
(write-buffered *(ebp+8) "81 0/subop/add %esp ")
(print-int32-buffered *(ebp+8) %eax)
(write-buffered *(ebp+8) "/imm32\n")
}
$emit-cleanup-code-until-target:continue:
2020-05-18 07:54:53 +00:00
# curr -= 8
81 5/subop/subtract %edx 8/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
2019-11-09 01:31:11 +00:00
# . 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
6082 - bugfix in spilling register vars In the process I'm starting to realize that my approach to avoiding spills isn't ideal. It works for local variables but not to avoid spilling outputs. To correctly decide whether to spill to an output register or not, we really need to analyze when a variable is live. If we don't do that, we'll end up in one of two bad situations: a) Don't spill the outermost use of an output register (or just the outermost scope in a function). This is weird because it's hard to explain to the programmer why they can overwrite a local with an output above a '{' but not below. b) Disallow overwriting entirely. This is easier to communicate but quite inconvenient. It's nice to be able to use eax for some temporary purpose before overwriting it with the final result of a function. If we instead track liveness, things are convenient and also easier to explain. If a temporary is used after the output has been written that's an obvious problem: "you clobbered the output". (It seems more reasonable to disallow multiple live ranges for the output. Once an output is written it can only be shadowed in a nested block.) That's the bad news. Now for some good news: One lovely property Mu the language has at the moment is that live ranges are guaranteed to be linear segments of code. We don't need to analyze loop-carried dependences. This means that we can decide whether a variable is live purely by scanning later statements for its use. (Defining 'register use' is slightly non-trivial; primitives must somehow specify when they read their output register.) So we don't actually need to worry about a loop reading a register with one type and writing to another type at the end of an iteration. The only way that can happen is if the write at the end was to a local variable, and we're guaranteeing that local variables will be reclaimed at the end of the iteration. So, the sequence of tasks: a) compute register liveness b1) verify that all register variables used at any point in a program are always the topmost use of that register. b2) decide whether to spill/shadow, clobber or flag an error. There's still the open question of where to attach liveness state. It can't be on a var, because liveness varies by use of the var. It can't be on a statement because we may want to know the liveness of variables not referenced in a given statement. Conceptually we want a matrix of locals x stmts (flattened). But I think it's simpler than that. We just want to know liveness at the time of variable declarations. A new register variable can be in one of three states w.r.t. its previous definition: either it's shadowing it, or it can clobber it, or there's a conflict and we need to raise an error. I think we can compute this information for each variable definition by an analysis similar to existing ones, maintaining a stack of variable definitions. The major difference is that we don't pop variables when a block ends. Details to be worked out. But when we do I hope to get these pending tests passing.
2020-03-06 08:06:42 +00:00
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
2020-04-24 01:56:08 +00:00
# var min/ecx: (addr handle var) = vars->data
81 0/subop/add %ecx 8/imm32
2020-05-19 06:26:40 +00:00
# var curr/edx: (addr handle var) = &vars->data[vars->top - 8]
81 5/subop/subtract %eax 8/imm32
8d/copy-address *(ecx+eax) 2/r32/edx
6082 - bugfix in spilling register vars In the process I'm starting to realize that my approach to avoiding spills isn't ideal. It works for local variables but not to avoid spilling outputs. To correctly decide whether to spill to an output register or not, we really need to analyze when a variable is live. If we don't do that, we'll end up in one of two bad situations: a) Don't spill the outermost use of an output register (or just the outermost scope in a function). This is weird because it's hard to explain to the programmer why they can overwrite a local with an output above a '{' but not below. b) Disallow overwriting entirely. This is easier to communicate but quite inconvenient. It's nice to be able to use eax for some temporary purpose before overwriting it with the final result of a function. If we instead track liveness, things are convenient and also easier to explain. If a temporary is used after the output has been written that's an obvious problem: "you clobbered the output". (It seems more reasonable to disallow multiple live ranges for the output. Once an output is written it can only be shadowed in a nested block.) That's the bad news. Now for some good news: One lovely property Mu the language has at the moment is that live ranges are guaranteed to be linear segments of code. We don't need to analyze loop-carried dependences. This means that we can decide whether a variable is live purely by scanning later statements for its use. (Defining 'register use' is slightly non-trivial; primitives must somehow specify when they read their output register.) So we don't actually need to worry about a loop reading a register with one type and writing to another type at the end of an iteration. The only way that can happen is if the write at the end was to a local variable, and we're guaranteeing that local variables will be reclaimed at the end of the iteration. So, the sequence of tasks: a) compute register liveness b1) verify that all register variables used at any point in a program are always the topmost use of that register. b2) decide whether to spill/shadow, clobber or flag an error. There's still the open question of where to attach liveness state. It can't be on a var, because liveness varies by use of the var. It can't be on a statement because we may want to know the liveness of variables not referenced in a given statement. Conceptually we want a matrix of locals x stmts (flattened). But I think it's simpler than that. We just want to know liveness at the time of variable declarations. A new register variable can be in one of three states w.r.t. its previous definition: either it's shadowing it, or it can clobber it, or there's a conflict and we need to raise an error. I think we can compute this information for each variable definition by an analysis similar to existing ones, maintaining a stack of variable definitions. The major difference is that we don't pop variables when a block ends. Details to be worked out. But when we do I hope to get these pending tests passing.
2020-03-06 08:06:42 +00:00
# var depth/ebx: int = v->block-depth
8b/-> *(ebp+8) 3/r32/ebx
2020-05-19 06:26:40 +00:00
8b/-> *(ebx+0x10) 3/r32/ebx # Var-block-depth
# var needle/esi: (addr array byte) = v->register
8b/-> *(ebp+8) 6/r32/esi
2020-05-19 06:26:40 +00:00
(lookup *(esi+0x18) *(esi+0x1c)) # Var-register Var-register => eax
89/<- %esi 0/r32/eax
{
$already-spilled-this-block?:loop:
# if (curr < min) break
39/compare %edx 1/r32/ecx
0f 82/jump-if-addr< break/disp32
2020-05-19 06:26:40 +00:00
# var cand/edi: (addr var) = lookup(*curr)
(lookup *edx *(edx+4)) # => eax
89/<- %edi 0/r32/eax
6082 - bugfix in spilling register vars In the process I'm starting to realize that my approach to avoiding spills isn't ideal. It works for local variables but not to avoid spilling outputs. To correctly decide whether to spill to an output register or not, we really need to analyze when a variable is live. If we don't do that, we'll end up in one of two bad situations: a) Don't spill the outermost use of an output register (or just the outermost scope in a function). This is weird because it's hard to explain to the programmer why they can overwrite a local with an output above a '{' but not below. b) Disallow overwriting entirely. This is easier to communicate but quite inconvenient. It's nice to be able to use eax for some temporary purpose before overwriting it with the final result of a function. If we instead track liveness, things are convenient and also easier to explain. If a temporary is used after the output has been written that's an obvious problem: "you clobbered the output". (It seems more reasonable to disallow multiple live ranges for the output. Once an output is written it can only be shadowed in a nested block.) That's the bad news. Now for some good news: One lovely property Mu the language has at the moment is that live ranges are guaranteed to be linear segments of code. We don't need to analyze loop-carried dependences. This means that we can decide whether a variable is live purely by scanning later statements for its use. (Defining 'register use' is slightly non-trivial; primitives must somehow specify when they read their output register.) So we don't actually need to worry about a loop reading a register with one type and writing to another type at the end of an iteration. The only way that can happen is if the write at the end was to a local variable, and we're guaranteeing that local variables will be reclaimed at the end of the iteration. So, the sequence of tasks: a) compute register liveness b1) verify that all register variables used at any point in a program are always the topmost use of that register. b2) decide whether to spill/shadow, clobber or flag an error. There's still the open question of where to attach liveness state. It can't be on a var, because liveness varies by use of the var. It can't be on a statement because we may want to know the liveness of variables not referenced in a given statement. Conceptually we want a matrix of locals x stmts (flattened). But I think it's simpler than that. We just want to know liveness at the time of variable declarations. A new register variable can be in one of three states w.r.t. its previous definition: either it's shadowing it, or it can clobber it, or there's a conflict and we need to raise an error. I think we can compute this information for each variable definition by an analysis similar to existing ones, maintaining a stack of variable definitions. The major difference is that we don't pop variables when a block ends. Details to be worked out. But when we do I hope to get these pending tests passing.
2020-03-06 08:06:42 +00:00
# if (cand->block-depth < depth) break
2020-05-19 06:26:40 +00:00
39/compare *(edi+0x10) 3/r32/ebx # Var-block-depth
6082 - bugfix in spilling register vars In the process I'm starting to realize that my approach to avoiding spills isn't ideal. It works for local variables but not to avoid spilling outputs. To correctly decide whether to spill to an output register or not, we really need to analyze when a variable is live. If we don't do that, we'll end up in one of two bad situations: a) Don't spill the outermost use of an output register (or just the outermost scope in a function). This is weird because it's hard to explain to the programmer why they can overwrite a local with an output above a '{' but not below. b) Disallow overwriting entirely. This is easier to communicate but quite inconvenient. It's nice to be able to use eax for some temporary purpose before overwriting it with the final result of a function. If we instead track liveness, things are convenient and also easier to explain. If a temporary is used after the output has been written that's an obvious problem: "you clobbered the output". (It seems more reasonable to disallow multiple live ranges for the output. Once an output is written it can only be shadowed in a nested block.) That's the bad news. Now for some good news: One lovely property Mu the language has at the moment is that live ranges are guaranteed to be linear segments of code. We don't need to analyze loop-carried dependences. This means that we can decide whether a variable is live purely by scanning later statements for its use. (Defining 'register use' is slightly non-trivial; primitives must somehow specify when they read their output register.) So we don't actually need to worry about a loop reading a register with one type and writing to another type at the end of an iteration. The only way that can happen is if the write at the end was to a local variable, and we're guaranteeing that local variables will be reclaimed at the end of the iteration. So, the sequence of tasks: a) compute register liveness b1) verify that all register variables used at any point in a program are always the topmost use of that register. b2) decide whether to spill/shadow, clobber or flag an error. There's still the open question of where to attach liveness state. It can't be on a var, because liveness varies by use of the var. It can't be on a statement because we may want to know the liveness of variables not referenced in a given statement. Conceptually we want a matrix of locals x stmts (flattened). But I think it's simpler than that. We just want to know liveness at the time of variable declarations. A new register variable can be in one of three states w.r.t. its previous definition: either it's shadowing it, or it can clobber it, or there's a conflict and we need to raise an error. I think we can compute this information for each variable definition by an analysis similar to existing ones, maintaining a stack of variable definitions. The major difference is that we don't pop variables when a block ends. Details to be worked out. But when we do I hope to get these pending tests passing.
2020-03-06 08:06:42 +00:00
0f 8c/jump-if-< break/disp32
2020-05-19 06:26:40 +00:00
# var cand-reg/edi: (array array byte) = cand->reg
(lookup *(edi+0x18) *(edi+0x1c)) # Var-register Var-register => eax
89/<- %edi 0/r32/eax
# if (cand-reg == null) continue
{
6082 - bugfix in spilling register vars In the process I'm starting to realize that my approach to avoiding spills isn't ideal. It works for local variables but not to avoid spilling outputs. To correctly decide whether to spill to an output register or not, we really need to analyze when a variable is live. If we don't do that, we'll end up in one of two bad situations: a) Don't spill the outermost use of an output register (or just the outermost scope in a function). This is weird because it's hard to explain to the programmer why they can overwrite a local with an output above a '{' but not below. b) Disallow overwriting entirely. This is easier to communicate but quite inconvenient. It's nice to be able to use eax for some temporary purpose before overwriting it with the final result of a function. If we instead track liveness, things are convenient and also easier to explain. If a temporary is used after the output has been written that's an obvious problem: "you clobbered the output". (It seems more reasonable to disallow multiple live ranges for the output. Once an output is written it can only be shadowed in a nested block.) That's the bad news. Now for some good news: One lovely property Mu the language has at the moment is that live ranges are guaranteed to be linear segments of code. We don't need to analyze loop-carried dependences. This means that we can decide whether a variable is live purely by scanning later statements for its use. (Defining 'register use' is slightly non-trivial; primitives must somehow specify when they read their output register.) So we don't actually need to worry about a loop reading a register with one type and writing to another type at the end of an iteration. The only way that can happen is if the write at the end was to a local variable, and we're guaranteeing that local variables will be reclaimed at the end of the iteration. So, the sequence of tasks: a) compute register liveness b1) verify that all register variables used at any point in a program are always the topmost use of that register. b2) decide whether to spill/shadow, clobber or flag an error. There's still the open question of where to attach liveness state. It can't be on a var, because liveness varies by use of the var. It can't be on a statement because we may want to know the liveness of variables not referenced in a given statement. Conceptually we want a matrix of locals x stmts (flattened). But I think it's simpler than that. We just want to know liveness at the time of variable declarations. A new register variable can be in one of three states w.r.t. its previous definition: either it's shadowing it, or it can clobber it, or there's a conflict and we need to raise an error. I think we can compute this information for each variable definition by an analysis similar to existing ones, maintaining a stack of variable definitions. The major difference is that we don't pop variables when a block ends. Details to be worked out. But when we do I hope to get these pending tests passing.
2020-03-06 08:06:42 +00:00
$already-spilled-this-block?:check-reg:
81 7/subop/compare %edi 0/imm32
2020-05-19 06:26:40 +00:00
0f 84/jump-if-= break/disp32
# if (cand-reg == needle) return true
(string-equal? %esi %edi) # => eax
3d/compare-eax-and 0/imm32/false
74/jump-if-= break/disp8
2020-05-19 06:26:40 +00:00
$already-spilled-this-block?:return-true:
b8/copy-to-eax 1/imm32/true
eb/jump $already-spilled-this-block?:end/disp8
}
$already-spilled-this-block?:continue:
2020-05-19 06:26:40 +00:00
# curr -= 8
81 5/subop/subtract %edx 8/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
6082 - bugfix in spilling register vars In the process I'm starting to realize that my approach to avoiding spills isn't ideal. It works for local variables but not to avoid spilling outputs. To correctly decide whether to spill to an output register or not, we really need to analyze when a variable is live. If we don't do that, we'll end up in one of two bad situations: a) Don't spill the outermost use of an output register (or just the outermost scope in a function). This is weird because it's hard to explain to the programmer why they can overwrite a local with an output above a '{' but not below. b) Disallow overwriting entirely. This is easier to communicate but quite inconvenient. It's nice to be able to use eax for some temporary purpose before overwriting it with the final result of a function. If we instead track liveness, things are convenient and also easier to explain. If a temporary is used after the output has been written that's an obvious problem: "you clobbered the output". (It seems more reasonable to disallow multiple live ranges for the output. Once an output is written it can only be shadowed in a nested block.) That's the bad news. Now for some good news: One lovely property Mu the language has at the moment is that live ranges are guaranteed to be linear segments of code. We don't need to analyze loop-carried dependences. This means that we can decide whether a variable is live purely by scanning later statements for its use. (Defining 'register use' is slightly non-trivial; primitives must somehow specify when they read their output register.) So we don't actually need to worry about a loop reading a register with one type and writing to another type at the end of an iteration. The only way that can happen is if the write at the end was to a local variable, and we're guaranteeing that local variables will be reclaimed at the end of the iteration. So, the sequence of tasks: a) compute register liveness b1) verify that all register variables used at any point in a program are always the topmost use of that register. b2) decide whether to spill/shadow, clobber or flag an error. There's still the open question of where to attach liveness state. It can't be on a var, because liveness varies by use of the var. It can't be on a statement because we may want to know the liveness of variables not referenced in a given statement. Conceptually we want a matrix of locals x stmts (flattened). But I think it's simpler than that. We just want to know liveness at the time of variable declarations. A new register variable can be in one of three states w.r.t. its previous definition: either it's shadowing it, or it can clobber it, or there's a conflict and we need to raise an error. I think we can compute this information for each variable definition by an analysis similar to existing ones, maintaining a stack of variable definitions. The major difference is that we don't pop variables when a block ends. Details to be worked out. But when we do I hope to get these pending tests passing.
2020-03-06 08:06:42 +00:00
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
2020-05-19 06:26:40 +00:00
same-register-spilled-before?: # v: (addr var), vars: (addr stack (handle var)), start: (addr var) -> result/eax: boolean
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
51/push-ecx
52/push-edx
53/push-ebx
56/push-esi
57/push-edi
# ecx = v
8b/-> *(ebp+8) 1/r32/ecx
2020-05-19 06:26:40 +00:00
# var reg/edx: (addr array byte) = lookup(v->register)
(lookup *(ecx+0x18) *(ecx+0x1c)) # Var-register Var-register => eax
89/<- %edx 0/r32/eax
# var depth/ebx: int = v->block-depth
2020-05-19 06:26:40 +00:00
8b/-> *(ecx+0x10) 3/r32/ebx # Var-block-depth
2020-04-24 01:56:08 +00:00
# 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
2020-04-24 01:56:08 +00:00
# var curr/esi: (addr handle var) = start
8b/-> *(ebp+0x10) 6/r32/esi
2020-05-19 06:26:40 +00:00
# curr -= 8
81 5/subop/subtract %esi 8/imm32
{
$same-register-spilled-before?:loop:
# if (curr < min) break
39/compare %esi 1/r32/ecx
0f 82/jump-if-addr< break/disp32
2020-05-19 06:26:40 +00:00
# var x/eax: (addr var) = lookup(*curr)
(lookup *esi *(esi+4)) # => eax
# if (x->block-depth < depth) break
2020-05-19 06:26:40 +00:00
39/compare *(eax+0x10) 3/r32/ebx # Var-block-depth
0f 8c/jump-if-< break/disp32
2020-03-08 02:59:57 +00:00
# if (x->register == 0) continue
2020-05-19 06:26:40 +00:00
81 7/subop/compare *(eax+0x18) 0/imm32 # Var-register
2020-03-08 02:59:57 +00:00
74/jump-if-= $same-register-spilled-before?:continue/disp8
# if (x->register == reg) return true
2020-05-19 06:26:40 +00:00
(lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax
2020-05-21 06:48:38 +00:00
(string-equal? %eax %edx) # => eax
3d/compare-eax-and 0/imm32/false
2020-05-19 06:26:40 +00:00
b8/copy-to-eax 1/imm32/true
75/jump-if-!= $same-register-spilled-before?:end/disp8
2020-03-08 02:59:57 +00:00
$same-register-spilled-before?:continue:
2020-05-19 06:26:40 +00:00
# curr -= 8
81 5/subop/subtract %esi 8/imm32
e9/jump loop/disp32
}
$same-register-spilled-before?:false:
b8/copy-to-eax 0/imm32/false
$same-register-spilled-before?:end:
# . restore registers
5f/pop-to-edi
5e/pop-to-esi
5b/pop-to-ebx
5a/pop-to-edx
59/pop-to-ecx
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
2020-02-07 05:15:34 +00:00
# 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
8b/-> *esi 0/r32/eax # Stack-top
3d/compare-eax-and 0/imm32
7e/jump-if-<= break/disp8
# var v/eax: (addr var) = lookup(vars[vars->top-8])
(lookup *(esi+eax) *(esi+eax+4)) # vars + 8 + vars->top - 8 => eax
# if (v->block-depth < until-block-depth) break
39/compare *(eax+0x10) 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+0x18) 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
}
2020-05-19 06:26:40 +00:00
(pop %esi) # => eax
(pop %esi) # => eax
e9/jump loop/disp32
}
$clean-up-blocks:end:
# . restore registers
5e/pop-to-esi
59/pop-to-ecx
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
emit-subx-var-def: # out: (addr buffered-file), stmt: (addr stmt)
2020-01-27 10:07:00 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
51/push-ecx
52/push-edx
2020-01-27 10:07:00 +00:00
# eax = stmt
8b/-> *(ebp+0xc) 0/r32/eax
2020-05-18 07:54:53 +00:00
# var v/ecx: (addr var)
(lookup *(eax+4) *(eax+8)) # Vardef-var Vardef-var => eax
89/<- %ecx 0/r32/eax
# v->block-depth = *Curr-block-depth
8b/-> *Curr-block-depth 0/r32/eax
2020-05-18 07:54:53 +00:00
89/<- *(ecx+0x10) 0/r32/eax # Var-block-depth
2020-03-12 02:55:45 +00:00
# var n/edx: int = size-of(stmt->var)
(size-of %ecx) # => eax
89/<- %edx 0/r32/eax
# *Curr-local-stack-offset -= n
2020-03-12 02:55:45 +00:00
29/subtract-from *Curr-local-stack-offset 2/r32/edx
# v->offset = *Curr-local-stack-offset
2020-03-12 02:55:45 +00:00
8b/-> *Curr-local-stack-offset 0/r32/eax
2020-05-18 07:54:53 +00:00
89/<- *(ecx+0x14) 0/r32/eax # Var-offset
2020-03-12 02:55:45 +00:00
# if v is an array, do something special
{
2020-05-18 07:54:53 +00:00
(lookup *(ecx+8) *(ecx+0xc)) # Var-type Var-type => eax
(is-mu-array? %eax) # => eax
2020-03-12 02:55:45 +00:00
3d/compare-eax-and 0/imm32/false
0f 84/jump-if-= break/disp32
# var array-size-without-size/edx: int = n-4
2020-03-12 02:55:45 +00:00
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
}
2020-01-27 10:07:00 +00:00
# while n > 0
{
2020-03-12 02:55:45 +00:00
81 7/subop/compare %edx 0/imm32
2020-01-27 10:07:00 +00:00
7e/jump-if-<= break/disp8
(emit-indent *(ebp+8) *Curr-block-depth)
(write-buffered *(ebp+8) "68/push 0/imm32\n")
2020-01-27 10:07:00 +00:00
# n -= 4
2020-03-12 02:55:45 +00:00
81 5/subop/subtract %edx 4/imm32
2020-01-27 10:07:00 +00:00
#
eb/jump loop/disp8
}
$emit-subx-var-def:end:
# . restore registers
5a/pop-to-edx
2020-01-27 10:07:00 +00:00
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)
2019-11-09 01:31:11 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
51/push-ecx
2020-03-07 23:48:11 +00:00
# - some special-case primitives that don't actually use the 'primitives' data structure
2020-05-13 07:51:31 +00:00
# var op/ecx: (addr array byte) = lookup(stmt->operation)
8b/-> *(ebp+0xc) 1/r32/ecx
2020-05-13 07:51:31 +00:00
(lookup *(ecx+4) *(ecx+8)) # Stmt1-operation Stmt1-operation => eax
89/<- %ecx 0/r32/eax
# array size
{
# if (!string-equal?(stmt->operation, "length")) break
2020-05-13 07:51:31 +00:00
(string-equal? %ecx "length") # => eax
3d/compare-eax-and 0/imm32
0f 84/jump-if-= break/disp32
2020-03-07 23:48:11 +00:00
(translate-mu-length-stmt *(ebp+8) *(ebp+0xc))
2020-02-21 23:36:18 +00:00
e9/jump $emit-subx-stmt:end/disp32
}
2020-03-07 23:48:11 +00:00
# index into array
{
2020-05-13 07:51:31 +00:00
# if (!string-equal?(stmt->operation, "index")) break
(string-equal? %ecx "index") # => eax
3d/compare-eax-and 0/imm32
0f 84/jump-if-= break/disp32
2020-03-07 23:48:11 +00:00
(translate-mu-index-stmt *(ebp+8) *(ebp+0xc))
2020-02-21 23:36:18 +00:00
e9/jump $emit-subx-stmt:end/disp32
}
# compute-offset for index into array
{
2020-05-13 07:51:31 +00:00
# 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
}
2020-03-07 23:48:11 +00:00
# get field from record
{
2020-05-13 07:51:31 +00:00
# if (!string-equal?(stmt->operation, "get")) break
(string-equal? %ecx "get") # => eax
3d/compare-eax-and 0/imm32
0f 84/jump-if-= break/disp32
2020-03-07 23:48:11 +00:00
(translate-mu-get-stmt *(ebp+8) *(ebp+0xc))
e9/jump $emit-subx-stmt:end/disp32
}
2020-03-07 23:48:11 +00:00
# - if stmt matches a primitive, emit it
2019-11-09 01:31:11 +00:00
{
2020-02-21 23:36:18 +00:00
$emit-subx-stmt:check-for-primitive:
2020-05-13 07:51:31 +00:00
# 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
2020-02-21 23:36:18 +00:00
$emit-subx-stmt:primitive:
(emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr
2020-02-21 23:36:18 +00:00
e9/jump $emit-subx-stmt:end/disp32
}
# - otherwise emit a call
# TODO: type-checking
2020-02-21 23:36:18 +00:00
$emit-subx-stmt:call:
(emit-call *(ebp+8) *(ebp+0xc))
2020-02-21 23:36:18 +00:00
$emit-subx-stmt:end:
2020-03-07 23:48:11 +00:00
# . 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)
2020-03-07 23:48:11 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
51/push-ecx
2020-05-24 20:27:08 +00:00
52/push-edx
53/push-ebx
2020-03-07 23:48:11 +00:00
# ecx = stmt
8b/-> *(ebp+0xc) 1/r32/ecx
#
(emit-indent *(ebp+8) *Curr-block-depth)
(write-buffered *(ebp+8) "8b/-> *")
2020-05-24 20:27:08 +00:00
# var base/ebx: (addr var) = inouts[0]
2020-05-21 07:01:50 +00:00
(lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax
(lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax
2020-05-24 20:27:08 +00:00
89/<- %ebx 0/r32/eax
2020-04-24 01:56:08 +00:00
# if base is an (addr array ...) in a register
2020-03-12 07:45:17 +00:00
{
2020-05-24 20:27:08 +00:00
81 7/subop/compare *(ebx+0x18)) 0/imm32 # Var-register
2020-03-12 07:45:17 +00:00
74/jump-if-= break/disp8
2020-05-24 20:27:08 +00:00
(lookup *(ebx+0x18) *(ebx+0x1c)) # Var-register Var-register => eax
2020-05-21 07:01:50 +00:00
(write-buffered *(ebp+8) %eax)
2020-03-12 07:45:17 +00:00
eb/jump $translate-mu-length-stmt:emit-output/disp8
}
# otherwise if base is an (array ...) on the stack
{
2020-05-24 20:27:08 +00:00
81 7/subop/compare *(ebx+0x14)) 0/imm32 # Var-offset
2020-03-12 07:45:17 +00:00
74/jump-if-= break/disp8
(write-buffered *(ebp+8) "(ebp+")
2020-05-24 20:27:08 +00:00
(print-int32-buffered *(ebp+8) *(ebx+0x14)) # Var-offset
2020-03-12 07:45:17 +00:00
(write-buffered *(ebp+8) ")")
}
$translate-mu-length-stmt:emit-output:
2020-03-07 23:48:11 +00:00
(write-buffered *(ebp+8) " ")
# outputs[0] "/r32"
2020-05-21 07:01:50 +00:00
(lookup *(ecx+0x14) *(ecx+0x18)) # Stmt1-outputs Stmt1-outputs => eax
(lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax
2020-05-24 20:27:08 +00:00
# edx = outputs[0]->register
2020-05-21 07:01:50 +00:00
(lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax
2020-05-24 20:27:08 +00:00
89/<- %edx 0/r32/eax
#
(get Registers %edx 0xc "Registers") # => eax
2020-03-07 23:48:11 +00:00
(print-int32-buffered *(ebp+8) *eax)
(write-buffered *(ebp+8) "/r32\n")
2020-05-24 20:27:08 +00:00
$translate-mu-length-stmt:check-power-of-2:
# ecx = size-of(element-type(base))
(array-element-type-id %ebx) # => eax
(size-of-type-id %eax) # => eax
89/<- %ecx 0/r32/eax
#
(power-of-2? %ecx) # => eax
3d/compare-eax-and 0/imm32/false
{
0f 84/jump-if-= break/disp32
$translate-mu-length-stmt:is-power-of-2:
(emit-indent *(ebp+8) *Curr-block-depth)
(write-buffered *(ebp+8) "c1/shift 5/subop/>> %")
(write-buffered *(ebp+8) %edx)
(write-buffered *(ebp+8) Space)
(num-shift-rights %ecx) # => eax
(print-int32-buffered *(ebp+8) %eax)
(write-buffered *(ebp+8) "/imm32\n")
eb/jump $translate-mu-length-stmt:end/disp8
}
{
75/jump-if-!= break/disp8
$translate-mu-length-stmt:not-power-of-2:
}
2020-03-07 23:48:11 +00:00
$translate-mu-length-stmt:end:
# . restore registers
2020-05-24 20:27:08 +00:00
5b/pop-to-ebx
2020-03-07 23:48:11 +00:00
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
2020-05-21 07:23:55 +00:00
# ecx = stmt
8b/-> *(ebp+0xc) 1/r32/ecx
2020-05-21 22:36:31 +00:00
# var base/ecx: (addr var) = stmt->inouts[0]
2020-05-21 07:23:55 +00:00
(lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax
(lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax
2020-05-21 22:36:31 +00:00
89/<- %ecx 0/r32/eax
# if (var->register) do one thing
{
2020-05-21 07:23:55 +00:00
81 7/subop/compare *(ecx+0x18) 0/imm32 # Var-register
74/jump-if-= break/disp8
# TODO: ensure there's no dereference
(translate-mu-index-stmt-with-array-in-register *(ebp+8) *(ebp+0xc))
eb/jump $translate-mu-index-stmt:end/disp8
}
# if (var->offset) do a different thing
{
2020-05-21 07:23:55 +00:00
81 7/subop/compare *(ecx+0x14) 0/imm32 # Var-offset
74/jump-if-= break/disp8
# TODO: ensure there's no dereference
(translate-mu-index-stmt-with-array-on-stack *(ebp+8) *(ebp+0xc))
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)
2020-03-07 23:48:11 +00:00
# . 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:
2020-03-07 23:48:11 +00:00
# ecx = stmt
8b/-> *(ebp+0xc) 1/r32/ecx
2020-05-21 07:23:55 +00:00
# var base/ebx: (addr var) = inouts[0]
(lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax
(lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax
89/<- %ebx 0/r32/eax
2020-03-07 23:48:11 +00:00
# print base->register " + "
2020-05-21 07:23:55 +00:00
(lookup *(ebx+0x18) *(ebx+0x1c)) # Var-register Var-register => eax
(write-buffered *(ebp+8) %eax)
2020-03-07 23:48:11 +00:00
(write-buffered *(ebp+8) " + ")
2020-05-21 22:36:31 +00:00
# var index/edx: (addr var) = inouts[1]
2020-05-21 07:23:55 +00:00
(lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax
(lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax
(lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax
89/<- %edx 0/r32/eax
# if index->register
2020-05-21 07:23:55 +00:00
81 7/subop/compare *(edx+0x18) 0/imm32 # Var-register
2020-03-07 23:48:11 +00:00
{
0f 84/jump-if-= break/disp32
$translate-mu-index-stmt-with-array-in-register:emit-register-index:
# if index is an int
2020-05-21 07:23:55 +00:00
(lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax
2020-05-21 22:36:31 +00:00
(is-simple-mu-type? %eax 1) # int => eax
3d/compare-eax-and 0/imm32/false
{
0f 84/jump-if-= break/disp32
$translate-mu-index-stmt-with-array-in-register:emit-int-register-index:
# print index->register "<<" log2(size-of(element(base->type))) " + 4) "
# . index->register "<<"
2020-05-21 07:23:55 +00:00
(lookup *(edx+0x18) *(edx+0x1c)) # Var-register Var-register => eax
(write-buffered *(ebp+8) %eax)
(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
2020-05-07 05:58:57 +00:00
(lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax
2020-04-12 09:33:01 +00:00
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 ...)
2020-05-21 07:23:55 +00:00
(lookup *(eax+4) *(eax+8)) # Tree-left Tree-left => eax
(is-simple-mu-type? %eax 7) # => eax
3d/compare-eax-and 0/imm32/false
{
0f 84/jump-if-= break/disp32
2020-05-21 22:36:31 +00:00
# print index->register
$translate-mu-index-stmt-with-array-in-register:emit-offset-register-index:
2020-05-21 07:23:55 +00:00
(lookup *(edx+0x18) *(edx+0x1c)) # Var-register Var-register => eax
(write-buffered *(ebp+8) %eax)
}
$translate-mu-index-stmt-with-array-in-register:emit-register-index-done:
2020-03-07 23:48:11 +00:00
(write-buffered *(ebp+8) " + 4) ")
e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
2020-03-07 23:48:11 +00:00
}
# otherwise if index is a literal
2020-05-21 07:23:55 +00:00
(lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax
(is-simple-mu-type? %eax 0) # => eax
2020-03-07 23:48:11 +00:00
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)
2020-05-21 07:23:55 +00:00
(lookup *edx *(edx+4)) # Var-name Var-name => eax
(parse-hex-int %eax) # => eax
2020-03-07 23:48:11 +00:00
89/<- %edx 0/r32/eax
# offset = idx-value * size-of(element(base->type))
2020-03-07 23:48:11 +00:00
(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
2020-03-07 23:48:11 +00:00
}
# otherwise abort
e9/jump $translate-mu-index-stmt-with-array:error1/disp32
$translate-mu-index-stmt-with-array-in-register:emit-output:
2020-03-07 23:48:11 +00:00
# outputs[0] "/r32"
8b/-> *(ebp+0xc) 1/r32/ecx
2020-05-21 07:23:55 +00:00
(lookup *(ecx+0x14) *(ecx+0x18)) # Stmt1-outputs Stmt1-outputs => eax
(lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax
(lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax
(get Registers %eax 0xc "Registers") # => eax: (addr int)
2020-03-07 23:48:11 +00:00
(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 + ")
2020-05-21 22:36:31 +00:00
# var curr/edx: (addr stmt-var) = lookup(stmt->inouts)
8b/-> *(ebp+0xc) 0/r32/eax
2020-05-21 22:36:31 +00:00
(lookup *(eax+0xc) *(eax+0x10)) # Stmt1-inouts Stmt1-inouts => eax
89/<- %edx 0/r32/eax
# var base/ecx: (addr var) = lookup(curr->value)
(lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax
89/<- %ecx 0/r32/eax
# var curr2/eax: (addr stmt-var) = lookup(curr->next)
(lookup *(edx+8) *(edx+0xc)) # Stmt-var-next Stmt-var-next => eax
# var index/edx: (handle var) = curr2->value
(lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax
89/<- %edx 0/r32/eax
# if index->register
2020-05-21 22:36:31 +00:00
81 7/subop/compare *(edx+0x18) 0/imm32 # Var-register
{
0f 84/jump-if-= break/disp32
$translate-mu-index-stmt-with-array-on-stack:emit-register-index:
# if index is an int
2020-05-21 22:36:31 +00:00
(lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax
(is-simple-mu-type? %eax 1) # int => eax
3d/compare-eax-and 0/imm32/false
{
0f 84/jump-if-= break/disp32
$translate-mu-index-stmt-with-array-on-stack:emit-int-register-index:
# print index->register "<<" log2(size-of(element-type(base))) " + " base->offset+4
# . inouts[1]->register "<<"
2020-05-21 22:36:31 +00:00
(lookup *(edx+0x18) *(edx+0x1c)) # Var-register Var-register => eax
(write-buffered *(ebp+8) %eax)
(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) " + ")
#
2020-05-21 22:36:31 +00:00
8b/-> *(ecx+0x14) 0/r32/eax # Var-offset
05/add-to-eax 4/imm32 # for array length
(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
2020-05-07 05:58:57 +00:00
(lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax
2020-04-12 09:33:01 +00:00
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 ...)
2020-05-21 22:36:31 +00:00
(lookup *(eax+4) *(eax+8)) # Tree-left Tree-left => eax
(is-simple-mu-type? %eax 7) # => eax
3d/compare-eax-and 0/imm32/false
{
0f 84/jump-if-= break/disp32
# print index->register
$translate-mu-index-stmt-with-array-on-stack:emit-offset-register-index:
2020-05-21 22:36:31 +00:00
(lookup *(edx+0x18) *(edx+0x1c)) # Var-register Var-register => eax
(write-buffered *(ebp+8) %eax)
}
$translate-mu-index-stmt-with-array-on-stack:emit-register-index-done:
(write-buffered *(ebp+8) ") ")
e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
}
# otherwise if index is a literal
2020-05-21 22:36:31 +00:00
(lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax
(is-simple-mu-type? %eax 0) # => eax
3d/compare-eax-and 0/imm32/false
{
0f 84/jump-if-= break/disp32
$translate-mu-index-stmt-with-array-on-stack:emit-literal-index:
# var idx-value/edx: int = parse-hex-int(index->name)
2020-05-21 22:36:31 +00:00
(lookup *edx *(edx+4)) # Var-name Var-name => eax
(parse-hex-int %eax) # Var-name => eax
89/<- %edx 0/r32/eax
# offset = idx-value * size-of(element-type(base->type))
(array-element-type-id %ecx) # => eax
(size-of-type-id %eax) # => eax
2020-05-21 22:36:31 +00:00
f7 4/subop/multiply-into-eax %edx # clobbers edx
# offset += base->offset
2020-05-21 22:36:31 +00:00
03/add *(ecx+0x14) 0/r32/eax # Var-offset
# offset += 4 for array size
05/add-to-eax 4/imm32
# TODO: check edx for overflow
# print offset
(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
2020-05-21 22:36:31 +00:00
(lookup *(eax+0x14) *(eax+0x18)) # Stmt1-outputs Stmt1-outputs => eax
(lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax
(lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax
(get Registers %eax 0xc "Registers") # => eax: (addr int)
(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/ebx: (addr stmt-var) = stmt->inouts[0]
(lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax
89/<- %ebx 0/r32/eax
$translate-mu-compute-index-stmt:emit-index:
(lookup *(ebx+8) *(ebx+0xc)) # Stmt-var-next Stmt-var-next => eax
(emit-subx-var-as-rm32 *(ebp+8) %eax)
(write-buffered *(ebp+8) Space)
$translate-mu-compute-index-stmt:emit-elem-size:
# var base/ebx: (addr var)
(lookup *ebx *(ebx+4)) # Stmt-var-value Stmt-var-value => eax
89/<- %ebx 0/r32/eax
# print 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"
(lookup *(ecx+0x14) *(ecx+0x18)) # Stmt1-outputs Stmt1-outputs => eax
(lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax
(lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax
(get Registers %eax 0xc "Registers") # => eax: (addr int)
(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)
2020-03-07 23:48:11 +00:00
# . 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)
2020-03-10 23:39:06 +00:00
(write-buffered *(ebp+8) "8d/copy-address ")
2020-03-07 23:48:11 +00:00
# ecx = stmt
8b/-> *(ebp+0xc) 1/r32/ecx
2020-03-10 23:39:06 +00:00
# var offset/edx: int = get offset of stmt
(mu-get-offset %ecx) # => eax
89/<- %edx 0/r32/eax
2020-05-22 21:43:26 +00:00
# var base/eax: (addr var) = stmt->inouts->value
(lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax
(lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax
2020-03-10 23:39:06 +00:00
# if base is in a register
2020-05-22 21:43:26 +00:00
81 7/subop/compare *(eax+0x18) 0/imm32 # Var-register
2020-03-10 23:39:06 +00:00
{
0f 84/jump-if-= break/disp32
$translate-mu-get-stmt:emit-register-input:
2020-05-22 21:43:26 +00:00
# emit "*(" base->register " + " offset ") "
2020-03-10 23:39:06 +00:00
(write-buffered *(ebp+8) "*(")
2020-05-22 21:43:26 +00:00
(lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax
(write-buffered *(ebp+8) %eax)
2020-03-10 23:39:06 +00:00
(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:
2020-05-22 21:43:26 +00:00
# emit "*(ebp + " inouts[0]->stack-offset + offset ") "
2020-03-10 23:39:06 +00:00
(write-buffered *(ebp+8) "*(ebp+")
2020-05-22 21:43:26 +00:00
03/add *(eax+0x14) 2/r32/edx # Var-offset
2020-03-10 23:39:06 +00:00
(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:
2020-05-22 21:43:26 +00:00
# var output/eax: (addr var) = stmt->outputs->value
(lookup *(ecx+0x14) *(ecx+0x18)) # Stmt1-outputs Stmt1-outputs => eax
(lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax
# emit offset->register "/r32"
(lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax
(get Registers %eax 0xc "Registers") # => eax: (addr int)
2020-03-07 23:48:11 +00:00
(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
2020-05-21 07:23:55 +00:00
(lookup *(eax+8) *(eax+0xc)) # Var-type Var-type => eax
# TODO: ensure type->left is 'addr'
2020-05-21 07:23:55 +00:00
(lookup *(eax+0xc) *(eax+0x10)) # Tree-right Tree-right => eax
# TODO: ensure that type->right is non-null
# TODO: ensure that type->right->left is 'array'
2020-05-21 07:23:55 +00:00
(lookup *(eax+0xc) *(eax+0x10)) # Tree-right Tree-right => eax
# TODO: ensure that type->right->right is non-null
2020-05-21 07:23:55 +00:00
(lookup *(eax+4) *(eax+8)) # Tree-left Tree-left => eax
2020-04-12 09:33:01 +00:00
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
2020-05-24 20:27:08 +00:00
power-of-2?: # n: int -> result/eax: boolean
# precondition: n is positive
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# eax = n
8b/-> *(ebp+8) 0/r32/eax
# if (n < 0) abort
3d/compare-eax-with 0/imm32
0f 8c/jump-if-< $power-of-2?:abort/disp32
# var tmp/eax: int = n-1
48/decrement-eax
# var tmp2/eax: int = n & tmp
23/and-> *(ebp+8) 0/r32/eax
# return (tmp2 == 0)
3d/compare-eax-and 0/imm32
0f 94/set-byte-if-= %al
81 4/subop/and %eax 0xff/imm32
$power-of-2?:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
$power-of-2?:abort:
(write-buffered Stderr "power-of-2?: negative number\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
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
2020-05-22 21:43:26 +00:00
# var second-inout/eax: (addr stmt-var) = stmt->inouts->next
2020-03-09 00:09:27 +00:00
8b/-> *(ebp+8) 0/r32/eax
2020-05-22 21:43:26 +00:00
(lookup *(eax+0xc) *(eax+0x10)) # Stmt1-inouts Stmt1-inouts => eax
(lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax
# var output-var/eax: (addr var) = second-inout->value
(lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax
2020-05-24 07:51:52 +00:00
#? (write-buffered Stderr "mu-get-offset: ")
#? (print-int32-buffered Stderr %eax)
#? (write-buffered Stderr " name: ")
#? 50/push-eax
#? (lookup *eax *(eax+4)) # Var-name
#? (write-buffered Stderr %eax)
#? 58/pop-to-eax
#? (write-buffered Stderr Newline)
#? (flush Stderr)
2020-05-22 21:43:26 +00:00
# return output-var->stack-offset
8b/-> *(eax+0x14) 0/r32/eax # Var-offset
2020-05-24 07:51:52 +00:00
#? (write-buffered Stderr "=> ")
#? (print-int32-buffered Stderr %eax)
#? (write-buffered Stderr Newline)
#? (flush Stderr)
$emit-get-offset:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
emit-subx-block: # out: (addr buffered-file), block: (addr block), vars: (addr stack (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
2020-05-18 00:59:12 +00:00
(lookup *(esi+0xc) *(esi+0x10)) # Block-var Block-var => eax
8b/-> *Curr-block-depth 1/r32/ecx
2020-05-18 00:59:12 +00:00
89/<- *(eax+0x10) 1/r32/ecx # Var-block-depth
# var stmts/eax: (addr list stmt) = lookup(block->statements)
(lookup *(esi+4) *(esi+8)) # Block-stmts Block-stmts => eax
#
{
$emit-subx-block:check-empty:
2020-02-22 03:38:11 +00:00
3d/compare-eax-and 0/imm32
0f 84/jump-if-= break/disp32
(emit-indent *(ebp+8) *Curr-block-depth)
(write-buffered *(ebp+8) "{\n")
2020-05-18 00:59:12 +00:00
# var v/ecx: (addr var) = lookup(block->var)
(lookup *(esi+0xc) *(esi+0x10)) # Block-var Block-var => eax
89/<- %ecx 0/r32/eax
#
2020-05-18 00:59:12 +00:00
(lookup *ecx *(ecx+4)) # Var-name Var-name => eax
(write-buffered *(ebp+8) %eax)
(write-buffered *(ebp+8) ":loop:\n")
ff 0/subop/increment *Curr-block-depth
2020-05-18 00:59:12 +00:00
(push *(ebp+0x10) *(esi+0xc)) # Block-var
(push *(ebp+0x10) *(esi+0x10)) # Block-var
2020-05-18 02:34:30 +00:00
# emit block->statements
(lookup *(esi+4) *(esi+8)) # Block-stmts Block-stmts => eax
(emit-subx-stmt-list *(ebp+8) %eax *(ebp+0x10))
(pop *(ebp+0x10)) # => eax
2020-05-18 00:59:12 +00:00
(pop *(ebp+0x10)) # => eax
ff 1/subop/decrement *Curr-block-depth
(emit-indent *(ebp+8) *Curr-block-depth)
(write-buffered *(ebp+8) "}\n")
2020-05-18 02:34:30 +00:00
(lookup *ecx *(ecx+4)) # Var-name Var-name => eax
(write-buffered *(ebp+8) %eax)
(write-buffered *(ebp+8) ":break:\n")
}
$emit-subx-block:end:
# . restore registers
5e/pop-to-esi
59/pop-to-ecx
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
# Primitives supported
2020-05-17 18:24:40 +00:00
# See mu_instructions for a summary of this linked-list data structure.
#
2019-12-26 08:28:16 +00:00
# For each operation, put variants with hard-coded registers before flexible ones.
#
2020-05-17 18:24:40 +00:00
# Unfortunately, our restrictions on addresses require that various fields in
# primitives be handles, which complicates these definitions.
# - we need to insert dummy fields all over the place for fake alloc-ids
# - we can't use our syntax sugar of quoted literals for string fields
#
# Fake alloc-ids are needed because our type definitions up top require
# handles but it's clearer to statically allocate these long-lived objects.
# Fake alloc-ids are perfectly safe, but they can't be reclaimed.
#
# Every 'object' below starts with a fake alloc-id. It may also contain other
# fake alloc-ids for various handle fields.
#
# I think of objects starting with a fake alloc-id as having type 'payload'.
# It's not really intended to be created dynamically; for that use `allocate`
# as usual.
#
# Idea for a notation to simplify such definitions:
2020-05-17 22:48:26 +00:00
# _Primitive-increment-eax: # (payload primitive)
# 0x11/alloc-id:fake:payload
# 0x11 @(0x11 "increment") # name
# 0 0 # inouts
# 0x11 @(0x11/payload
# 0x11 @(0x11/payload # List-value
# 0 0 # Var-name
# 0x11 @(0x11 # Var-type
# 1/is-atom
# 1/value 0/unused # Tree-left
# 0 0 # Tree-right
# )
# 1 # block-depth
# 0 # stack-offset
# 0x11 @(0x11 "eax") # Var-register
# )
# 0 0) # List-next
# ...
2020-05-17 01:36:42 +00:00
# _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
2020-05-17 18:24:40 +00:00
Primitives: # (addr primitive)
2019-12-26 08:28:16 +00:00
# - increment/decrement
2020-05-17 18:24:40 +00:00
_Primitive-increment-eax: # (addr primitive)
2019-12-26 09:49:41 +00:00
# var/eax <- increment => 40/increment-eax
0x11/imm32/alloc-id:fake
_string-increment/imm32/name
0/imm32/no-inouts
0/imm32/no-inouts
0x11/imm32/alloc-id:fake
Single-int-var-in-eax/imm32/outputs
0x11/imm32/alloc-id:fake
_string_40_increment_eax/imm32/subx-name
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
0/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
2020-05-17 01:36:42 +00:00
_Primitive-increment-ecx/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-increment-ecx: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 09:49:41 +00:00
# var/ecx <- increment => 41/increment-ecx
0x11/imm32/alloc-id:fake
_string-increment/imm32/name
0/imm32/no-inouts
0/imm32/no-inouts
0x11/imm32/alloc-id:fake
Single-int-var-in-ecx/imm32/outputs
0x11/imm32/alloc-id:fake
_string_41_increment_ecx/imm32/subx-name
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
0/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
2020-05-17 01:36:42 +00:00
_Primitive-increment-edx/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-increment-edx: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 09:49:41 +00:00
# var/edx <- increment => 42/increment-edx
0x11/imm32/alloc-id:fake
_string-increment/imm32/name
0/imm32/no-inouts
0/imm32/no-inouts
0x11/imm32/alloc-id:fake
Single-int-var-in-edx/imm32/outputs
0x11/imm32/alloc-id:fake
_string_42_increment_edx/imm32/subx-name
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
0/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
2020-05-17 01:36:42 +00:00
_Primitive-increment-ebx/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-increment-ebx: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 09:49:41 +00:00
# var/ebx <- increment => 43/increment-ebx
0x11/imm32/alloc-id:fake
_string-increment/imm32/name
0/imm32/no-inouts
0/imm32/no-inouts
0x11/imm32/alloc-id:fake
Single-int-var-in-ebx/imm32/outputs
0x11/imm32/alloc-id:fake
_string_43_increment_ebx/imm32/subx-name
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
0/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
2020-05-17 01:36:42 +00:00
_Primitive-increment-esi/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-increment-esi: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 09:49:41 +00:00
# var/esi <- increment => 46/increment-esi
0x11/imm32/alloc-id:fake
_string-increment/imm32/name
0/imm32/no-inouts
0/imm32/no-inouts
0x11/imm32/alloc-id:fake
Single-int-var-in-esi/imm32/outputs
0x11/imm32/alloc-id:fake
_string_46_increment_esi/imm32/subx-name
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
0/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
2020-05-17 01:36:42 +00:00
_Primitive-increment-edi/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-increment-edi: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 09:49:41 +00:00
# var/edi <- increment => 47/increment-edi
0x11/imm32/alloc-id:fake
_string-increment/imm32/name
0/imm32/no-inouts
0/imm32/no-inouts
0x11/imm32/alloc-id:fake
Single-int-var-in-edi/imm32/outputs
0x11/imm32/alloc-id:fake
_string_47_increment_edi/imm32/subx-name
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
0/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
2020-05-17 01:36:42 +00:00
_Primitive-decrement-eax/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-decrement-eax: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 09:49:41 +00:00
# var/eax <- decrement => 48/decrement-eax
0x11/imm32/alloc-id:fake
_string-decrement/imm32/name
0/imm32/no-inouts
0/imm32/no-inouts
0x11/imm32/alloc-id:fake
Single-int-var-in-eax/imm32/outputs
0x11/imm32/alloc-id:fake
_string_48_decrement_eax/imm32/subx-name
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
0/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
2020-05-17 01:36:42 +00:00
_Primitive-decrement-ecx/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-decrement-ecx: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 09:49:41 +00:00
# var/ecx <- decrement => 49/decrement-ecx
0x11/imm32/alloc-id:fake
_string-decrement/imm32/name
0/imm32/no-inouts
0/imm32/no-inouts
0x11/imm32/alloc-id:fake
Single-int-var-in-ecx/imm32/outputs
0x11/imm32/alloc-id:fake
_string_49_decrement_ecx/imm32/subx-name
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
0/imm32/output-is-write-only
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake
2020-05-17 01:36:42 +00:00
_Primitive-decrement-edx/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-decrement-edx: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 09:49:41 +00:00
# var/edx <- decrement => 4a/decrement-edx
0x11/imm32/alloc-id:fake
_string-decrement/imm32/name
0/imm32/no-inouts
0/imm32/no-inouts
0x11/imm32/alloc-id:fake
Single-int-var-in-edx/imm32/outputs
0x11/imm32/alloc-id:fake
_string_4a_decrement_edx/imm32/subx-name
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
0/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
2020-05-17 01:36:42 +00:00
_Primitive-decrement-ebx/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-decrement-ebx: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 09:49:41 +00:00
# var/ebx <- decrement => 4b/decrement-ebx
0x11/imm32/alloc-id:fake
_string-decrement/imm32/name
0/imm32/no-inouts
0/imm32/no-inouts
0x11/imm32/alloc-id:fake
Single-int-var-in-ebx/imm32/outputs
0x11/imm32/alloc-id:fake
_string_4b_decrement_ebx/imm32/subx-name
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
0/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
2020-05-17 01:36:42 +00:00
_Primitive-decrement-esi/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-decrement-esi: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 09:49:41 +00:00
# var/esi <- decrement => 4e/decrement-esi
0x11/imm32/alloc-id:fake
_string-decrement/imm32/name
0/imm32/no-inouts
0/imm32/no-inouts
0x11/imm32/alloc-id:fake
Single-int-var-in-esi/imm32/outputs
0x11/imm32/alloc-id:fake
_string_4e_decrement_esi/imm32/subx-name
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
0/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
2020-05-17 01:36:42 +00:00
_Primitive-decrement-edi/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-decrement-edi: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 09:49:41 +00:00
# var/edi <- decrement => 4f/decrement-edi
0x11/imm32/alloc-id:fake
_string-decrement/imm32/name
0/imm32/no-inouts
0/imm32/no-inouts
0x11/imm32/alloc-id:fake
Single-int-var-in-edi/imm32/outputs
0x11/imm32/alloc-id:fake
_string_4f_decrement_edi/imm32/subx-name
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
0/imm32/output-is-write-only
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake
2020-05-17 01:36:42 +00:00
_Primitive-increment-mem/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-increment-mem: # (payload primitive)
2020-05-17 07:30:33 +00:00
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
2020-05-17 01:36:42 +00:00
_Primitive-increment-reg/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-increment-reg: # (payload primitive)
2020-05-17 07:30:33 +00:00
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
2020-05-17 01:36:42 +00:00
_Primitive-decrement-mem/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-decrement-mem: # (payload primitive)
2020-05-17 07:30:33 +00:00
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
2020-05-17 01:36:42 +00:00
_Primitive-decrement-reg/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-decrement-reg: # (payload primitive)
2020-05-17 07:30:33 +00:00
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
2019-12-26 08:28:16 +00:00
_Primitive-add-to-eax/imm32/next
# - add
2020-05-17 18:24:40 +00:00
_Primitive-add-to-eax: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 09:49:41 +00:00
# var/eax <- add lit => 05/add-to-eax lit/imm32
0x11/imm32/alloc-id:fake
_string-add/imm32/name
0x11/imm32/alloc-id:fake
2019-12-26 08:28:16 +00:00
Single-lit-var/imm32/inouts
0x11/imm32/alloc-id:fake
2019-12-26 08:28:16 +00:00
Single-int-var-in-eax/imm32/outputs
0x11/imm32/alloc-id:fake
_string_05_add_to_eax/imm32/subx-name
2019-12-26 08:28:16 +00:00
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
2020-05-17 18:24:40 +00:00
_Primitive-add-reg-to-reg: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 10:21:55 +00:00
# var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32
0x11/imm32/alloc-id:fake
_string-add/imm32/name
0x11/imm32/alloc-id:fake
Single-int-var-in-some-register/imm32/inouts
0x11/imm32/alloc-id:fake
Single-int-var-in-some-register/imm32/outputs
0x11/imm32/alloc-id:fake
_string_01_add_to/imm32/subx-name
3/imm32/rm32-is-first-output
1/imm32/r32-is-first-inout
0/imm32/no-imm32
0/imm32/no-disp32
0/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
2019-11-27 01:41:25 +00:00
_Primitive-add-reg-to-mem/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-add-reg-to-mem: # (payload primitive)
2020-05-17 18:00:25 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 10:21:55 +00:00
# add-to var1 var2/reg => 01/add-to var1 var2/r32
0x11/imm32/alloc-id:fake
_string-add-to/imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 03:43:20 +00:00
Two-args-int-stack-int-reg/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_01_add_to/imm32/subx-name
2019-11-27 01:41:25 +00:00
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
2019-11-27 01:41:25 +00:00
_Primitive-add-mem-to-reg/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-add-mem-to-reg: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 08:28:16 +00:00
# var1/reg <- add var2 => 03/add var2/rm32 var1/r32
0x11/imm32/alloc-id:fake
_string-add/imm32/name
0x11/imm32/alloc-id:fake
Single-int-var-in-mem/imm32/inouts
0x11/imm32/alloc-id:fake
2019-11-27 01:41:25 +00:00
Single-int-var-in-some-register/imm32/outputs
0x11/imm32/alloc-id:fake
_string_03_add/imm32/subx-name
2019-11-27 01:41:25 +00:00
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
2020-05-17 18:24:40 +00:00
_Primitive-add-lit-to-reg: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
# var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32
0x11/imm32/alloc-id:fake
_string-add/imm32/name
0x11/imm32/alloc-id:fake
Single-lit-var/imm32/inouts
0x11/imm32/alloc-id:fake
Single-int-var-in-some-register/imm32/outputs
0x11/imm32/alloc-id:fake
_string_81_subop_add/imm32/subx-name
3/imm32/rm32-is-first-output
0/imm32/no-r32
1/imm32/imm32-is-first-inout
0/imm32/no-disp32
0/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
2019-11-27 01:41:25 +00:00
_Primitive-add-lit-to-mem/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-add-lit-to-mem: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-11-27 01:41:25 +00:00
# add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32
0x11/imm32/alloc-id:fake
_string-add-to/imm32/name
0x11/imm32/alloc-id:fake
2019-11-27 01:41:25 +00:00
Int-var-and-literal/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_81_subop_add/imm32/subx-name
2019-11-27 01:41:25 +00:00
1/imm32/rm32-is-first-inout
0/imm32/no-r32
2020-01-30 03:43:20 +00:00
2/imm32/imm32-is-second-inout
0/imm32/no-disp32
0/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
2019-12-26 08:28:16 +00:00
_Primitive-subtract-from-eax/imm32/next
# - subtract
2020-05-17 18:24:40 +00:00
_Primitive-subtract-from-eax: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 09:49:41 +00:00
# var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32
0x11/imm32/alloc-id:fake
_string-subtract/imm32/name
0x11/imm32/alloc-id:fake
2019-12-26 08:28:16 +00:00
Single-lit-var/imm32/inouts
0x11/imm32/alloc-id:fake
2019-12-26 08:28:16 +00:00
Single-int-var-in-eax/imm32/outputs
0x11/imm32/alloc-id:fake
_string_2d_subtract_from_eax/imm32/subx-name
2019-12-26 08:28:16 +00:00
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
2019-12-26 08:28:16 +00:00
_Primitive-subtract-reg-from-reg/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-subtract-reg-from-reg: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 10:21:55 +00:00
# var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32
0x11/imm32/alloc-id:fake
_string-subtract/imm32/name
0x11/imm32/alloc-id:fake
2019-12-26 08:28:16 +00:00
Single-int-var-in-some-register/imm32/inouts
0x11/imm32/alloc-id:fake
2019-12-26 08:28:16 +00:00
Single-int-var-in-some-register/imm32/outputs
0x11/imm32/alloc-id:fake
_string_29_subtract_from/imm32/subx-name
2019-12-26 08:28:16 +00:00
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
2019-12-26 08:28:16 +00:00
_Primitive-subtract-reg-from-mem/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-subtract-reg-from-mem: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 10:21:55 +00:00
# subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32
0x11/imm32/alloc-id:fake
_string-subtract-from/imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 03:43:20 +00:00
Two-args-int-stack-int-reg/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_29_subtract_from/imm32/subx-name
2019-12-26 08:28:16 +00:00
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
2019-12-26 08:28:16 +00:00
_Primitive-subtract-mem-from-reg/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-subtract-mem-from-reg: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 08:28:16 +00:00
# var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32
0x11/imm32/alloc-id:fake
_string-subtract/imm32/name
0x11/imm32/alloc-id:fake
Single-int-var-in-mem/imm32/inouts
0x11/imm32/alloc-id:fake
2019-12-26 08:28:16 +00:00
Single-int-var-in-some-register/imm32/outputs
0x11/imm32/alloc-id:fake
_string_2b_subtract/imm32/subx-name
2019-12-26 08:28:16 +00:00
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
2019-12-26 08:28:16 +00:00
_Primitive-subtract-lit-from-reg/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-subtract-lit-from-reg: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 08:28:16 +00:00
# var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32
0x11/imm32/alloc-id:fake
_string-subtract/imm32/name
0x11/imm32/alloc-id:fake
2019-12-26 08:28:16 +00:00
Single-lit-var/imm32/inouts
0x11/imm32/alloc-id:fake
2019-12-26 08:28:16 +00:00
Single-int-var-in-some-register/imm32/outputs
0x11/imm32/alloc-id:fake
_string_81_subop_subtract/imm32/subx-name
2019-12-26 08:28:16 +00:00
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
2020-05-17 23:42:28 +00:00
0x11/imm32/alloc-id:fake
2019-12-26 08:28:16 +00:00
_Primitive-subtract-lit-from-mem/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-subtract-lit-from-mem: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 08:28:16 +00:00
# subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32
0x11/imm32/alloc-id:fake
_string-subtract-from/imm32/name
0x11/imm32/alloc-id:fake
2019-12-26 08:28:16 +00:00
Int-var-and-literal/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_81_subop_subtract/imm32/subx-name
2019-12-26 08:28:16 +00:00
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
2019-12-26 09:49:41 +00:00
_Primitive-and-with-eax/imm32/next
# - and
2020-05-17 18:24:40 +00:00
_Primitive-and-with-eax: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 09:49:41 +00:00
# var/eax <- and lit => 25/and-with-eax lit/imm32
0x11/imm32/alloc-id:fake
_string-and/imm32/name
0x11/imm32/alloc-id:fake
2019-12-26 09:49:41 +00:00
Single-lit-var/imm32/inouts
0x11/imm32/alloc-id:fake
2019-12-26 09:49:41 +00:00
Single-int-var-in-eax/imm32/outputs
0x11/imm32/alloc-id:fake
_string_25_and_with_eax/imm32/subx-name
2019-12-26 09:49:41 +00:00
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
2019-12-26 09:49:41 +00:00
_Primitive-and-reg-with-reg/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-and-reg-with-reg: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 10:21:55 +00:00
# var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32
0x11/imm32/alloc-id:fake
_string-and/imm32/name
0x11/imm32/alloc-id:fake
2019-12-26 09:49:41 +00:00
Single-int-var-in-some-register/imm32/inouts
0x11/imm32/alloc-id:fake
2019-12-26 09:49:41 +00:00
Single-int-var-in-some-register/imm32/outputs
0x11/imm32/alloc-id:fake
_string_21_and_with/imm32/subx-name
2019-12-26 09:49:41 +00:00
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
2019-12-26 09:49:41 +00:00
_Primitive-and-reg-with-mem/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-and-reg-with-mem: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 10:21:55 +00:00
# and-with var1 var2/reg => 21/and-with var1 var2/r32
0x11/imm32/alloc-id:fake
_string-and-with/imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 03:43:20 +00:00
Two-args-int-stack-int-reg/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_21_and_with/imm32/subx-name
2019-12-26 09:49:41 +00:00
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
2019-12-26 09:49:41 +00:00
_Primitive-and-mem-with-reg/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-and-mem-with-reg: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 09:49:41 +00:00
# var1/reg <- and var2 => 23/and var2/rm32 var1/r32
0x11/imm32/alloc-id:fake
_string-and/imm32/name
0x11/imm32/alloc-id:fake
Single-int-var-in-mem/imm32/inouts
0x11/imm32/alloc-id:fake
2019-12-26 09:49:41 +00:00
Single-int-var-in-some-register/imm32/outputs
0x11/imm32/alloc-id:fake
_string_23_and/imm32/subx-name
2019-12-26 09:49:41 +00:00
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
2019-12-26 09:49:41 +00:00
_Primitive-and-lit-with-reg/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-and-lit-with-reg: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 09:49:41 +00:00
# var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32
0x11/imm32/alloc-id:fake
_string-and/imm32/name
0x11/imm32/alloc-id:fake
2019-12-26 09:49:41 +00:00
Single-lit-var/imm32/inouts
0x11/imm32/alloc-id:fake
2019-12-26 09:49:41 +00:00
Single-int-var-in-some-register/imm32/outputs
0x11/imm32/alloc-id:fake
_string_81_subop_and/imm32/subx-name
2019-12-26 09:49:41 +00:00
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
2019-12-26 09:49:41 +00:00
_Primitive-and-lit-with-mem/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-and-lit-with-mem: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 09:49:41 +00:00
# and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32
0x11/imm32/alloc-id:fake
_string-and-with/imm32/name
0x11/imm32/alloc-id:fake
2019-12-26 09:49:41 +00:00
Int-var-and-literal/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_81_subop_and/imm32/subx-name
2019-12-26 09:49:41 +00:00
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
2019-12-26 09:49:41 +00:00
_Primitive-or-with-eax/imm32/next
# - or
2020-05-17 18:24:40 +00:00
_Primitive-or-with-eax: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 09:49:41 +00:00
# var/eax <- or lit => 0d/or-with-eax lit/imm32
0x11/imm32/alloc-id:fake
_string-or/imm32/name
0x11/imm32/alloc-id:fake
2019-12-26 09:49:41 +00:00
Single-lit-var/imm32/inouts
0x11/imm32/alloc-id:fake
2019-12-26 09:49:41 +00:00
Single-int-var-in-eax/imm32/outputs
0x11/imm32/alloc-id:fake
_string_0d_or_with_eax/imm32/subx-name
2019-12-26 09:49:41 +00:00
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
2019-12-26 09:49:41 +00:00
_Primitive-or-reg-with-reg/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-or-reg-with-reg: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 10:21:55 +00:00
# var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32
0x11/imm32/alloc-id:fake
_string-or/imm32/name
0x11/imm32/alloc-id:fake
2019-12-26 09:49:41 +00:00
Single-int-var-in-some-register/imm32/inouts
0x11/imm32/alloc-id:fake
2019-12-26 09:49:41 +00:00
Single-int-var-in-some-register/imm32/outputs
0x11/imm32/alloc-id:fake
_string_09_or_with/imm32/subx-name
2019-12-26 09:49:41 +00:00
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
2019-12-26 09:49:41 +00:00
_Primitive-or-reg-with-mem/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-or-reg-with-mem: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 10:21:55 +00:00
# or-with var1 var2/reg => 09/or-with var1 var2/r32
0x11/imm32/alloc-id:fake
_string-or-with/imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 03:43:20 +00:00
Two-args-int-stack-int-reg/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_09_or_with/imm32/subx-name
2019-12-26 09:49:41 +00:00
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
2019-12-26 09:49:41 +00:00
_Primitive-or-mem-with-reg/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-or-mem-with-reg: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 09:49:41 +00:00
# var1/reg <- or var2 => 0b/or var2/rm32 var1/r32
0x11/imm32/alloc-id:fake
_string-or/imm32/name
0x11/imm32/alloc-id:fake
Single-int-var-in-mem/imm32/inouts
0x11/imm32/alloc-id:fake
2019-12-26 09:49:41 +00:00
Single-int-var-in-some-register/imm32/outputs
0x11/imm32/alloc-id:fake
_string_0b_or/imm32/subx-name
2019-12-26 09:49:41 +00:00
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
2019-12-26 09:49:41 +00:00
_Primitive-or-lit-with-reg/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-or-lit-with-reg: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 09:49:41 +00:00
# var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32
0x11/imm32/alloc-id:fake
_string-or/imm32/name
0x11/imm32/alloc-id:fake
2019-12-26 09:49:41 +00:00
Single-lit-var/imm32/inouts
0x11/imm32/alloc-id:fake
2019-12-26 09:49:41 +00:00
Single-int-var-in-some-register/imm32/outputs
0x11/imm32/alloc-id:fake
_string_81_subop_or/imm32/subx-name
2019-12-26 09:49:41 +00:00
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
2019-12-26 09:49:41 +00:00
_Primitive-or-lit-with-mem/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-or-lit-with-mem: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 09:49:41 +00:00
# or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32
0x11/imm32/alloc-id:fake
_string-or-with/imm32/name
0x11/imm32/alloc-id:fake
2019-12-26 09:49:41 +00:00
Int-var-and-literal/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_81_subop_or/imm32/subx-name
2019-12-26 09:49:41 +00:00
1/imm32/rm32-is-first-inout
0/imm32/no-r32
2020-01-30 03:43:20 +00:00
2/imm32/imm32-is-second-inout
0/imm32/no-disp32
0/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
2019-12-26 09:49:41 +00:00
_Primitive-xor-with-eax/imm32/next
# - xor
2020-05-17 18:24:40 +00:00
_Primitive-xor-with-eax: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 09:49:41 +00:00
# var/eax <- xor lit => 35/xor-with-eax lit/imm32
0x11/imm32/alloc-id:fake
_string-xor/imm32/name
0x11/imm32/alloc-id:fake
2019-12-26 09:49:41 +00:00
Single-lit-var/imm32/inouts
0x11/imm32/alloc-id:fake
2019-12-26 09:49:41 +00:00
Single-int-var-in-eax/imm32/outputs
0x11/imm32/alloc-id:fake
_string_35_xor_with_eax/imm32/subx-name
2019-12-26 09:49:41 +00:00
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
2019-12-26 09:49:41 +00:00
_Primitive-xor-reg-with-reg/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-xor-reg-with-reg: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 10:21:55 +00:00
# var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32
0x11/imm32/alloc-id:fake
_string-xor/imm32/name
0x11/imm32/alloc-id:fake
2019-12-26 09:49:41 +00:00
Single-int-var-in-some-register/imm32/inouts
0x11/imm32/alloc-id:fake
2019-12-26 09:49:41 +00:00
Single-int-var-in-some-register/imm32/outputs
0x11/imm32/alloc-id:fake
_string_31_xor_with/imm32/subx-name
2019-12-26 09:49:41 +00:00
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
2019-12-26 09:49:41 +00:00
_Primitive-xor-reg-with-mem/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-xor-reg-with-mem: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 10:21:55 +00:00
# xor-with var1 var2/reg => 31/xor-with var1 var2/r32
0x11/imm32/alloc-id:fake
_string-xor-with/imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 03:43:20 +00:00
Two-args-int-stack-int-reg/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_31_xor_with/imm32/subx-name
2019-12-26 09:49:41 +00:00
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
2019-12-26 09:49:41 +00:00
_Primitive-xor-mem-with-reg/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-xor-mem-with-reg: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 09:49:41 +00:00
# var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32
0x11/imm32/alloc-id:fake
_string-xor/imm32/name
0x11/imm32/alloc-id:fake
Single-int-var-in-mem/imm32/inouts
0x11/imm32/alloc-id:fake
2019-12-26 09:49:41 +00:00
Single-int-var-in-some-register/imm32/outputs
0x11/imm32/alloc-id:fake
_string_33_xor/imm32/subx-name
2019-12-26 09:49:41 +00:00
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
2019-12-26 09:49:41 +00:00
_Primitive-xor-lit-with-reg/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-xor-lit-with-reg: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 09:49:41 +00:00
# var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32
0x11/imm32/alloc-id:fake
_string-xor/imm32/name
0x11/imm32/alloc-id:fake
2019-12-26 09:49:41 +00:00
Single-lit-var/imm32/inouts
0x11/imm32/alloc-id:fake
2019-12-26 09:49:41 +00:00
Single-int-var-in-some-register/imm32/outputs
0x11/imm32/alloc-id:fake
_string_81_subop_xor/imm32/subx-name
2019-12-26 09:49:41 +00:00
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
2019-12-26 09:49:41 +00:00
_Primitive-xor-lit-with-mem/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-xor-lit-with-mem: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 09:49:41 +00:00
# xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32
0x11/imm32/alloc-id:fake
_string-xor-with/imm32/name
0x11/imm32/alloc-id:fake
2019-12-26 09:49:41 +00:00
Int-var-and-literal/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_81_subop_xor/imm32/subx-name
2019-12-26 09:49:41 +00:00
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
2019-12-26 10:21:55 +00:00
_Primitive-copy-to-eax/imm32/next
# - copy
2020-05-17 18:24:40 +00:00
_Primitive-copy-to-eax: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 10:21:55 +00:00
# var/eax <- copy lit => b8/copy-to-eax lit/imm32
0x11/imm32/alloc-id:fake
_string-copy/imm32/name
0x11/imm32/alloc-id:fake
2019-12-26 10:21:55 +00:00
Single-lit-var/imm32/inouts
0x11/imm32/alloc-id:fake
2019-12-26 10:21:55 +00:00
Single-int-var-in-eax/imm32/outputs
0x11/imm32/alloc-id:fake
_string_b8_copy_to_eax/imm32/subx-name
2019-12-26 10:21:55 +00:00
0/imm32/no-rm32
0/imm32/no-r32
1/imm32/imm32-is-first-inout
0/imm32/no-disp32
2019-12-26 10:21:55 +00:00
1/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
2019-12-26 10:21:55 +00:00
_Primitive-copy-to-ecx/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-copy-to-ecx: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 10:21:55 +00:00
# var/ecx <- copy lit => b9/copy-to-ecx lit/imm32
0x11/imm32/alloc-id:fake
_string-copy/imm32/name
0x11/imm32/alloc-id:fake
2019-12-26 10:21:55 +00:00
Single-lit-var/imm32/inouts
0x11/imm32/alloc-id:fake
2019-12-26 10:21:55 +00:00
Single-int-var-in-ecx/imm32/outputs
0x11/imm32/alloc-id:fake
_string_b9_copy_to_ecx/imm32/subx-name
2019-12-26 10:21:55 +00:00
0/imm32/no-rm32
0/imm32/no-r32
1/imm32/imm32-is-first-inout
0/imm32/no-disp32
2019-12-26 10:21:55 +00:00
1/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
2019-12-26 10:21:55 +00:00
_Primitive-copy-to-edx/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-copy-to-edx: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 10:21:55 +00:00
# var/edx <- copy lit => ba/copy-to-edx lit/imm32
0x11/imm32/alloc-id:fake
_string-copy/imm32/name
0x11/imm32/alloc-id:fake
2019-12-26 10:21:55 +00:00
Single-lit-var/imm32/inouts
0x11/imm32/alloc-id:fake
2019-12-26 10:21:55 +00:00
Single-int-var-in-edx/imm32/outputs
0x11/imm32/alloc-id:fake
_string_ba_copy_to_edx/imm32/subx-name
2019-12-26 10:21:55 +00:00
0/imm32/no-rm32
0/imm32/no-r32
1/imm32/imm32-is-first-inout
0/imm32/no-disp32
2019-12-26 10:21:55 +00:00
1/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
2019-12-26 10:21:55 +00:00
_Primitive-copy-to-ebx/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-copy-to-ebx: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 10:21:55 +00:00
# var/ebx <- copy lit => bb/copy-to-ebx lit/imm32
0x11/imm32/alloc-id:fake
_string-copy/imm32/name
0x11/imm32/alloc-id:fake
2019-12-26 10:21:55 +00:00
Single-lit-var/imm32/inouts
0x11/imm32/alloc-id:fake
2019-12-26 10:21:55 +00:00
Single-int-var-in-ebx/imm32/outputs
0x11/imm32/alloc-id:fake
_string_bb_copy_to_ebx/imm32/subx-name
2019-12-26 10:21:55 +00:00
0/imm32/no-rm32
0/imm32/no-r32
1/imm32/imm32-is-first-inout
0/imm32/no-disp32
2019-12-26 10:21:55 +00:00
1/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
2019-12-26 10:21:55 +00:00
_Primitive-copy-to-esi/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-copy-to-esi: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 10:21:55 +00:00
# var/esi <- copy lit => be/copy-to-esi lit/imm32
0x11/imm32/alloc-id:fake
_string-copy/imm32/name
0x11/imm32/alloc-id:fake
2019-12-26 10:21:55 +00:00
Single-lit-var/imm32/inouts
0x11/imm32/alloc-id:fake
2019-12-26 10:21:55 +00:00
Single-int-var-in-esi/imm32/outputs
0x11/imm32/alloc-id:fake
_string_be_copy_to_esi/imm32/subx-name
2019-12-26 10:21:55 +00:00
0/imm32/no-rm32
0/imm32/no-r32
1/imm32/imm32-is-first-inout
0/imm32/no-disp32
2019-12-26 10:21:55 +00:00
1/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
2019-12-26 10:21:55 +00:00
_Primitive-copy-to-edi/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-copy-to-edi: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 10:21:55 +00:00
# var/edi <- copy lit => bf/copy-to-edi lit/imm32
0x11/imm32/alloc-id:fake
_string-copy/imm32/name
0x11/imm32/alloc-id:fake
2019-12-26 10:21:55 +00:00
Single-lit-var/imm32/inouts
0x11/imm32/alloc-id:fake
2019-12-26 10:21:55 +00:00
Single-int-var-in-edi/imm32/outputs
0x11/imm32/alloc-id:fake
_string_bf_copy_to_edi/imm32/subx-name
2019-12-26 10:21:55 +00:00
0/imm32/no-rm32
0/imm32/no-r32
1/imm32/imm32-is-first-inout
0/imm32/no-disp32
2019-12-26 10:21:55 +00:00
1/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
2019-12-26 10:21:55 +00:00
_Primitive-copy-reg-to-reg/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-copy-reg-to-reg: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
# var1/reg <- copy var2/reg => 89/<- var1/rm32 var2/r32
0x11/imm32/alloc-id:fake
_string-copy/imm32/name
0x11/imm32/alloc-id:fake
2019-12-26 10:21:55 +00:00
Single-int-var-in-some-register/imm32/inouts
0x11/imm32/alloc-id:fake
2019-12-26 10:21:55 +00:00
Single-int-var-in-some-register/imm32/outputs
0x11/imm32/alloc-id:fake
_string_89_<-/imm32/subx-name
2019-12-26 10:21:55 +00:00
3/imm32/rm32-is-first-output
1/imm32/r32-is-first-inout
0/imm32/no-imm32
0/imm32/no-disp32
2019-12-26 10:21:55 +00:00
1/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
2019-12-26 10:21:55 +00:00
_Primitive-copy-reg-to-mem/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-copy-reg-to-mem: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
# copy-to var1 var2/reg => 89/<- var1 var2/r32
0x11/imm32/alloc-id:fake
_string-copy-to/imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 03:43:20 +00:00
Two-args-int-stack-int-reg/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_89_<-/imm32/subx-name
2019-12-26 10:21:55 +00:00
1/imm32/rm32-is-first-inout
2/imm32/r32-is-second-inout
0/imm32/no-imm32
0/imm32/no-disp32
2019-12-26 10:21:55 +00:00
1/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
2019-12-26 10:21:55 +00:00
_Primitive-copy-mem-to-reg/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-copy-mem-to-reg: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
# var1/reg <- copy var2 => 8b/-> var2/rm32 var1/r32
0x11/imm32/alloc-id:fake
_string-copy/imm32/name
0x11/imm32/alloc-id:fake
Single-int-var-in-mem/imm32/inouts
0x11/imm32/alloc-id:fake
2019-12-26 10:21:55 +00:00
Single-int-var-in-some-register/imm32/outputs
0x11/imm32/alloc-id:fake
_string_8b_->/imm32/subx-name
2019-12-26 10:21:55 +00:00
1/imm32/rm32-is-first-inout
3/imm32/r32-is-first-output
0/imm32/no-imm32
0/imm32/no-disp32
2019-12-26 10:21:55 +00:00
1/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
2019-12-26 10:21:55 +00:00
_Primitive-copy-lit-to-reg/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-copy-lit-to-reg: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 10:21:55 +00:00
# var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32
0x11/imm32/alloc-id:fake
_string-copy/imm32/name
0x11/imm32/alloc-id:fake
2019-12-26 10:21:55 +00:00
Single-lit-var/imm32/inouts
0x11/imm32/alloc-id:fake
2019-12-26 10:21:55 +00:00
Single-int-var-in-some-register/imm32/outputs
0x11/imm32/alloc-id:fake
_string_c7_subop_copy/imm32/subx-name
2019-12-26 10:21:55 +00:00
3/imm32/rm32-is-first-output
0/imm32/no-r32
1/imm32/imm32-is-first-inout
0/imm32/no-disp32
2019-12-26 10:21:55 +00:00
1/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
2019-12-26 10:21:55 +00:00
_Primitive-copy-lit-to-mem/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-copy-lit-to-mem: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2019-12-26 10:21:55 +00:00
# copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32
0x11/imm32/alloc-id:fake
_string-copy-to/imm32/name
0x11/imm32/alloc-id:fake
2019-12-26 10:21:55 +00:00
Int-var-and-literal/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_c7_subop_copy/imm32/subx-name
2019-12-26 10:21:55 +00:00
1/imm32/rm32-is-first-inout
0/imm32/no-r32
2/imm32/imm32-is-first-inout
0/imm32/no-disp32
2019-12-26 10:21:55 +00:00
1/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
_Primitive-address/imm32/next
# - address
2020-05-17 18:24:40 +00:00
_Primitive-address: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
# var1/reg <- address var2 => 8d/copy-address var2/rm32 var1/r32
0x11/imm32/alloc-id:fake
_string-address/imm32/name
0x11/imm32/alloc-id:fake
Single-int-var-in-mem/imm32/inouts
0x11/imm32/alloc-id:fake
Single-addr-var-in-some-register/imm32/outputs
0x11/imm32/alloc-id:fake
_string_8d_copy_address/imm32/subx-name
1/imm32/rm32-is-first-inout
3/imm32/r32-is-first-output
0/imm32/no-imm32
0/imm32/no-disp32
1/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
2020-01-30 03:43:20 +00:00
_Primitive-compare-mem-with-reg/imm32/next
# - compare
2020-05-17 18:24:40 +00:00
_Primitive-compare-mem-with-reg: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
# compare var1 var2/reg => 39/compare var1/rm32 var2/r32
0x11/imm32/alloc-id:fake
_string-compare/imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 03:43:20 +00:00
Two-args-int-stack-int-reg/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_39_compare->/imm32/subx-name
2020-01-30 03:43:20 +00:00
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
2020-01-30 03:43:20 +00:00
_Primitive-compare-reg-with-mem/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-compare-reg-with-mem: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
# compare var1/reg var2 => 3b/compare<- var2/rm32 var1/r32
0x11/imm32/alloc-id:fake
_string-compare/imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 03:43:20 +00:00
Two-args-int-reg-int-stack/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_3b_compare<-/imm32/subx-name
2020-01-30 03:43:20 +00:00
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
2020-01-30 03:43:20 +00:00
_Primitive-compare-eax-with-literal/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-compare-eax-with-literal: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2020-01-30 03:43:20 +00:00
# compare var1/eax n => 3d/compare-eax-with n/imm32
0x11/imm32/alloc-id:fake
_string-compare/imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 03:43:20 +00:00
Two-args-int-eax-int-literal/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_3d_compare_eax_with/imm32/subx-name
2020-01-30 03:43:20 +00:00
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
2020-05-17 18:24:40 +00:00
_Primitive-compare-reg-with-literal: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
# compare var1/reg n => 81 7/subop/compare %reg n/imm32
0x11/imm32/alloc-id:fake
_string-compare/imm32/name
0x11/imm32/alloc-id:fake
Int-var-in-register-and-literal/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_81_subop_compare/imm32/subx-name
1/imm32/rm32-is-first-inout
0/imm32/no-r32
2/imm32/imm32-is-second-inout
0/imm32/no-disp32
0/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
_Primitive-compare-mem-with-literal/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-compare-mem-with-literal: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2020-01-30 03:43:20 +00:00
# compare var1 n => 81 7/subop/compare *(ebp+___) n/imm32
0x11/imm32/alloc-id:fake
_string-compare/imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 03:43:20 +00:00
Int-var-and-literal/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_81_subop_compare/imm32/subx-name
2020-01-30 03:43:20 +00:00
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
2020-01-30 07:10:08 +00:00
_Primitive-multiply-reg-by-mem/imm32/next
# - multiply
2020-05-17 18:24:40 +00:00
_Primitive-multiply-reg-by-mem: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
2020-01-30 07:10:08 +00:00
# var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
0x11/imm32/alloc-id:fake
_string-multiply/imm32/name
0x11/imm32/alloc-id:fake
Single-int-var-in-mem/imm32/inouts
0x11/imm32/alloc-id:fake
2020-01-30 07:10:08 +00:00
Single-int-var-in-some-register/imm32/outputs
0x11/imm32/alloc-id:fake
_string_0f_af_multiply/imm32/subx-name
2020-01-30 07:10:08 +00:00
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
2020-01-29 07:44:04 +00:00
_Primitive-break-if-addr</imm32/next
# - branches
2020-05-17 18:24:40 +00:00
_Primitive-break-if-addr<: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-break-if-addr</imm32/name
2020-05-17 01:37:45 +00:00
0/imm32/no-inouts
0/imm32/no-inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_82_jump_break/imm32/subx-name
2020-01-29 07:44:04 +00:00
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
2020-01-29 07:44:04 +00:00
0/imm32/no-output
0x11/imm32/alloc-id:fake
2020-01-29 07:44:04 +00:00
_Primitive-break-if-addr>=/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-break-if-addr>=: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-break-if-addr>=/imm32/name
2020-05-17 01:37:45 +00:00
0/imm32/no-inouts
0/imm32/no-inouts
0/imm32/no-outputs
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_83_jump_break/imm32/subx-name
2020-01-29 07:44:04 +00:00
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
2020-01-29 07:44:04 +00:00
0/imm32/no-output
0x11/imm32/alloc-id:fake
2020-01-29 07:44:04 +00:00
_Primitive-break-if-=/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-break-if-=: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-break-if-=/imm32/name
2020-05-17 01:37:45 +00:00
0/imm32/no-inouts
0/imm32/no-inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_84_jump_break/imm32/subx-name
2020-01-29 07:44:04 +00:00
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
2020-01-29 07:44:04 +00:00
0/imm32/no-output
0x11/imm32/alloc-id:fake
2020-01-29 07:44:04 +00:00
_Primitive-break-if-!=/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-break-if-!=: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-break-if-!=/imm32/name
2020-05-17 01:37:45 +00:00
0/imm32/no-inouts
0/imm32/no-inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_85_jump_break/imm32/subx-name
2020-01-29 07:44:04 +00:00
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
2020-01-29 07:44:04 +00:00
0/imm32/no-output
0x11/imm32/alloc-id:fake
2020-01-29 07:44:04 +00:00
_Primitive-break-if-addr<=/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-break-if-addr<=: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-break-if-addr<=/imm32/name
2020-05-17 01:37:45 +00:00
0/imm32/no-inouts
0/imm32/no-inouts
0/imm32/no-outputs
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_86_jump_break/imm32/subx-name
2020-01-29 07:44:04 +00:00
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
2020-01-29 07:44:04 +00:00
0/imm32/no-output
0x11/imm32/alloc-id:fake
2020-01-29 07:44:04 +00:00
_Primitive-break-if-addr>/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-break-if-addr>: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-break-if-addr>/imm32/name
2020-05-17 01:37:45 +00:00
0/imm32/no-inouts
0/imm32/no-inouts
0/imm32/no-outputs
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_87_jump_break/imm32/subx-name
2020-01-29 07:44:04 +00:00
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
2020-01-29 07:44:04 +00:00
0/imm32/no-output
0x11/imm32/alloc-id:fake
2020-01-29 07:44:04 +00:00
_Primitive-break-if-</imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-break-if-<: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-break-if-</imm32/name
2020-05-17 01:37:45 +00:00
0/imm32/no-inouts
0/imm32/no-inouts
0/imm32/no-outputs
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_8c_jump_break/imm32/subx-name
2020-01-29 07:44:04 +00:00
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
2020-01-29 07:44:04 +00:00
0/imm32/no-output
0x11/imm32/alloc-id:fake
2020-01-29 07:44:04 +00:00
_Primitive-break-if->=/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-break-if->=: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-break-if->=/imm32/name
2020-05-17 01:37:45 +00:00
0/imm32/no-inouts
0/imm32/no-inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_8d_jump_break/imm32/subx-name
2020-01-29 07:44:04 +00:00
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
2020-01-29 07:44:04 +00:00
0/imm32/no-output
0x11/imm32/alloc-id:fake
2020-01-29 07:44:04 +00:00
_Primitive-break-if-<=/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-break-if-<=: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-break-if-<=/imm32/name
2020-05-17 01:37:45 +00:00
0/imm32/no-inouts
0/imm32/no-inouts
0/imm32/no-outputs
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_8e_jump_break/imm32/subx-name
2020-01-29 07:44:04 +00:00
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
2020-01-29 07:44:04 +00:00
0/imm32/no-output
0x11/imm32/alloc-id:fake
2020-01-29 07:44:04 +00:00
_Primitive-break-if->/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-break-if->: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-break-if->/imm32/name
2020-05-17 01:37:45 +00:00
0/imm32/no-inouts
0/imm32/no-inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_8f_jump_break/imm32/subx-name
2020-01-29 07:44:04 +00:00
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
2020-01-29 07:44:04 +00:00
0/imm32/no-output
0x11/imm32/alloc-id:fake
2020-02-18 08:08:20 +00:00
_Primitive-break/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-break: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-break/imm32/name
2020-05-17 01:37:45 +00:00
0/imm32/no-inouts
0/imm32/no-inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_e9_jump_break/imm32/subx-name
2020-02-18 08:08:20 +00:00
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
2020-01-29 07:44:04 +00:00
_Primitive-loop-if-addr</imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-loop-if-addr<: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-loop-if-addr</imm32/name
2020-05-17 01:37:45 +00:00
0/imm32/no-inouts
0/imm32/no-inouts
0/imm32/no-outputs
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_82_jump_loop/imm32/subx-name
2020-01-29 07:44:04 +00:00
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
2020-01-29 07:44:04 +00:00
0/imm32/no-output
0x11/imm32/alloc-id:fake
2020-01-29 07:44:04 +00:00
_Primitive-loop-if-addr>=/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-loop-if-addr>=: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-loop-if-addr>=/imm32/name
2020-05-17 01:37:45 +00:00
0/imm32/no-inouts
0/imm32/no-inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_83_jump_loop/imm32/subx-name
2020-01-29 07:44:04 +00:00
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
2020-01-29 07:44:04 +00:00
0/imm32/no-output
0x11/imm32/alloc-id:fake
2020-01-29 07:44:04 +00:00
_Primitive-loop-if-=/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-loop-if-=: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-loop-if-=/imm32/name
2020-05-17 01:37:45 +00:00
0/imm32/no-inouts
0/imm32/no-inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_84_jump_loop/imm32/subx-name
2020-01-29 07:44:04 +00:00
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
2020-01-29 07:44:04 +00:00
0/imm32/no-output
0x11/imm32/alloc-id:fake
2020-01-29 07:44:04 +00:00
_Primitive-loop-if-!=/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-loop-if-!=: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-loop-if-!=/imm32/name
2020-05-17 01:37:45 +00:00
0/imm32/no-inouts
0/imm32/no-inouts
0/imm32/no-outputs
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_85_jump_loop/imm32/subx-name
2020-01-29 07:44:04 +00:00
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
2020-01-29 07:44:04 +00:00
0/imm32/no-output
0x11/imm32/alloc-id:fake
2020-01-29 07:44:04 +00:00
_Primitive-loop-if-addr<=/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-loop-if-addr<=: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-loop-if-addr<=/imm32/name
2020-05-17 01:37:45 +00:00
0/imm32/no-inouts
0/imm32/no-inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_86_jump_loop/imm32/subx-name
2020-01-29 07:44:04 +00:00
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
2020-01-29 07:44:04 +00:00
0/imm32/no-output
0x11/imm32/alloc-id:fake
2020-01-29 07:44:04 +00:00
_Primitive-loop-if-addr>/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-loop-if-addr>: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-loop-if-addr>/imm32/name
2020-05-17 01:37:45 +00:00
0/imm32/no-inouts
0/imm32/no-inouts
0/imm32/no-outputs
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_87_jump_loop/imm32/subx-name
2020-01-29 07:44:04 +00:00
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
2020-01-29 07:44:04 +00:00
0/imm32/no-output
0x11/imm32/alloc-id:fake
2020-01-29 07:44:04 +00:00
_Primitive-loop-if-</imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-loop-if-<: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-loop-if-</imm32/name
2020-05-17 01:37:45 +00:00
0/imm32/no-inouts
0/imm32/no-inouts
0/imm32/no-outputs
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_8c_jump_loop/imm32/subx-name
2020-01-29 07:44:04 +00:00
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
2020-01-29 07:44:04 +00:00
0/imm32/no-output
0x11/imm32/alloc-id:fake
2020-01-29 07:44:04 +00:00
_Primitive-loop-if->=/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-loop-if->=: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-loop-if->=/imm32/name
2020-05-17 01:37:45 +00:00
0/imm32/no-inouts
0/imm32/no-inouts
0/imm32/no-outputs
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_8d_jump_loop/imm32/subx-name
2020-01-29 07:44:04 +00:00
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
2020-01-29 07:44:04 +00:00
0/imm32/no-output
0x11/imm32/alloc-id:fake
2020-01-29 07:44:04 +00:00
_Primitive-loop-if-<=/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-loop-if-<=: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-loop-if-<=/imm32/name
2020-05-17 01:37:45 +00:00
0/imm32/no-inouts
0/imm32/no-inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_8e_jump_loop/imm32/subx-name
2020-01-29 07:44:04 +00:00
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
2020-01-29 07:44:04 +00:00
0/imm32/no-output
0x11/imm32/alloc-id:fake
2020-01-29 07:44:04 +00:00
_Primitive-loop-if->/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-loop-if->: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-loop-if->/imm32/name
2020-05-17 01:37:45 +00:00
0/imm32/no-inouts
0/imm32/no-inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_8f_jump_loop/imm32/subx-name
2020-01-29 07:44:04 +00:00
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
2020-01-29 07:44:04 +00:00
0/imm32/no-output
0x11/imm32/alloc-id:fake
2020-01-29 07:44:04 +00:00
_Primitive-loop/imm32/next # we probably don't need an unconditional break
2020-05-17 18:24:40 +00:00
_Primitive-loop: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-loop/imm32/name
2020-05-17 01:37:45 +00:00
0/imm32/no-inouts
0/imm32/no-inouts
0/imm32/no-outputs
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_e9_jump_loop/imm32/subx-name
2020-01-29 07:44:04 +00:00
0/imm32/no-rm32
0/imm32/no-r32
0/imm32/no-imm32
0/imm32/no-disp32
2020-01-29 07:44:04 +00:00
0/imm32/no-output
0x11/imm32/alloc-id:fake
2020-01-30 01:34:07 +00:00
_Primitive-break-if-addr<-named/imm32/next
# - branches to named blocks
2020-05-17 18:24:40 +00:00
_Primitive-break-if-addr<-named: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-break-if-addr</imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 01:34:07 +00:00
Single-lit-var/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_82_jump_label/imm32/subx-name
2020-01-30 01:34:07 +00:00
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
2020-01-30 01:34:07 +00:00
_Primitive-break-if-addr>=-named/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-break-if-addr>=-named: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-break-if-addr>=/imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 01:34:07 +00:00
Single-lit-var/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_83_jump_label/imm32/subx-name
2020-01-30 01:34:07 +00:00
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
2020-01-30 01:34:07 +00:00
_Primitive-break-if-=-named/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-break-if-=-named: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-break-if-=/imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 01:34:07 +00:00
Single-lit-var/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_84_jump_label/imm32/subx-name
2020-01-30 01:34:07 +00:00
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
2020-01-30 01:34:07 +00:00
_Primitive-break-if-!=-named/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-break-if-!=-named: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-break-if-!=/imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 01:34:07 +00:00
Single-lit-var/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_85_jump_label/imm32/subx-name
2020-01-30 01:34:07 +00:00
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
2020-01-30 01:34:07 +00:00
_Primitive-break-if-addr<=-named/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-break-if-addr<=-named: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-break-if-addr<=/imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 01:34:07 +00:00
Single-lit-var/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_86_jump_label/imm32/subx-name
2020-01-30 01:34:07 +00:00
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
2020-01-30 01:34:07 +00:00
_Primitive-break-if-addr>-named/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-break-if-addr>-named: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-break-if-addr>/imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 01:34:07 +00:00
Single-lit-var/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_87_jump_label/imm32/subx-name
2020-01-30 01:34:07 +00:00
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
2020-01-30 01:34:07 +00:00
_Primitive-break-if-<-named/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-break-if-<-named: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-break-if-</imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 01:34:07 +00:00
Single-lit-var/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_8c_jump_label/imm32/subx-name
2020-01-30 01:34:07 +00:00
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
2020-01-30 01:34:07 +00:00
_Primitive-break-if->=-named/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-break-if->=-named: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-break-if->=/imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 01:34:07 +00:00
Single-lit-var/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_8d_jump_label/imm32/subx-name
2020-01-30 01:34:07 +00:00
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
2020-01-30 01:34:07 +00:00
_Primitive-break-if-<=-named/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-break-if-<=-named: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-break-if-<=/imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 01:34:07 +00:00
Single-lit-var/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_8e_jump_label/imm32/subx-name
2020-01-30 01:34:07 +00:00
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
2020-01-30 01:34:07 +00:00
_Primitive-break-if->-named/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-break-if->-named: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-break-if->/imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 01:34:07 +00:00
Single-lit-var/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_8f_jump_label/imm32/subx-name
2020-01-30 01:34:07 +00:00
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
2020-02-18 08:08:20 +00:00
_Primitive-break-named/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-break-named: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-break/imm32/name
0x11/imm32/alloc-id:fake
2020-02-18 08:08:20 +00:00
Single-lit-var/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_e9_jump_label/imm32/subx-name
2020-02-18 08:08:20 +00:00
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
2020-01-30 01:34:07 +00:00
_Primitive-loop-if-addr<-named/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-loop-if-addr<-named: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-loop-if-addr</imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 01:34:07 +00:00
Single-lit-var/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_82_jump_label/imm32/subx-name
2020-01-30 01:34:07 +00:00
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
2020-01-30 01:34:07 +00:00
_Primitive-loop-if-addr>=-named/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-loop-if-addr>=-named: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-loop-if-addr>=/imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 01:34:07 +00:00
Single-lit-var/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_83_jump_label/imm32/subx-name
2020-01-30 01:34:07 +00:00
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
2020-01-30 01:34:07 +00:00
_Primitive-loop-if-=-named/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-loop-if-=-named: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-loop-if-=/imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 01:34:07 +00:00
Single-lit-var/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_84_jump_label/imm32/subx-name
2020-01-30 01:34:07 +00:00
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
2020-01-30 01:34:07 +00:00
_Primitive-loop-if-!=-named/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-loop-if-!=-named: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-loop-if-!=/imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 01:34:07 +00:00
Single-lit-var/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_85_jump_label/imm32/subx-name
2020-01-30 01:34:07 +00:00
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
2020-01-30 01:34:07 +00:00
_Primitive-loop-if-addr<=-named/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-loop-if-addr<=-named: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-loop-if-addr<=/imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 01:34:07 +00:00
Single-lit-var/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_86_jump_label/imm32/subx-name
2020-01-30 01:34:07 +00:00
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
2020-01-30 01:34:07 +00:00
_Primitive-loop-if-addr>-named/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-loop-if-addr>-named: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-loop-if-addr>/imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 01:34:07 +00:00
Single-lit-var/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_87_jump_label/imm32/subx-name
2020-01-30 01:34:07 +00:00
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
2020-01-30 01:34:07 +00:00
_Primitive-loop-if-<-named/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-loop-if-<-named: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-loop-if-</imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 01:34:07 +00:00
Single-lit-var/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_8c_jump_label/imm32/subx-name
2020-01-30 01:34:07 +00:00
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
2020-01-30 01:34:07 +00:00
_Primitive-loop-if->=-named/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-loop-if->=-named: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-loop-if->=/imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 01:34:07 +00:00
Single-lit-var/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_8d_jump_label/imm32/subx-name
2020-01-30 01:34:07 +00:00
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
2020-01-30 01:34:07 +00:00
_Primitive-loop-if-<=-named/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-loop-if-<=-named: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-loop-if-<=/imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 01:34:07 +00:00
Single-lit-var/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_8e_jump_label/imm32/subx-name
2020-01-30 01:34:07 +00:00
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
2020-01-30 01:34:07 +00:00
_Primitive-loop-if->-named/imm32/next
2020-05-17 18:24:40 +00:00
_Primitive-loop-if->-named: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-loop-if->/imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 01:34:07 +00:00
Single-lit-var/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_0f_8f_jump_label/imm32/subx-name
2020-01-30 01:34:07 +00:00
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
2020-01-30 01:34:07 +00:00
_Primitive-loop-named/imm32/next # we probably don't need an unconditional break
2020-05-17 18:24:40 +00:00
_Primitive-loop-named: # (payload primitive)
2020-05-17 07:30:33 +00:00
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
_string-loop/imm32/name
0x11/imm32/alloc-id:fake
2020-01-30 01:34:07 +00:00
Single-lit-var/imm32/inouts
2020-05-17 01:37:45 +00:00
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_e9_jump_label/imm32/subx-name
2020-01-30 01:34:07 +00:00
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
# string literals for Mu instructions
2020-05-17 18:24:40 +00:00
_string-add: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "add"
0x3/imm32/size
0x61/a 0x64/d 0x64/d
2020-05-17 18:24:40 +00:00
_string-address: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "address"
0x7/imm32/size
0x61/a 0x64/d 0x64/d 0x72/r 0x65/e 0x73/s 0x73/s
2020-05-17 18:24:40 +00:00
_string-add-to: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "add-to"
0x6/imm32/size
0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
2020-05-17 18:24:40 +00:00
_string-and: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "and"
0x3/imm32/size
0x61/a 0x6e/n 0x64/d
2020-05-17 18:24:40 +00:00
_string-and-with: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "and-with"
0x8/imm32/size
0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
2020-05-17 18:24:40 +00:00
_string-break: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "break"
0x5/imm32/size
0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k
2020-05-17 18:24:40 +00:00
_string-break-if-<: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "break-if-<"
0xa/imm32/size
0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
2020-05-17 18:24:40 +00:00
_string-break-if-<=: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "break-if-<="
0xb/imm32/size
0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
2020-05-17 18:24:40 +00:00
_string-break-if-=: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "break-if-="
0xa/imm32/size
0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
2020-05-17 18:24:40 +00:00
_string-break-if->: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "break-if->"
0xa/imm32/size
0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
2020-05-17 18:24:40 +00:00
_string-break-if->=: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "break-if->="
0xb/imm32/size
0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
2020-05-17 18:24:40 +00:00
_string-break-if-!=: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "break-if-!="
0xb/imm32/size
0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
2020-05-17 18:24:40 +00:00
_string-break-if-addr<: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "break-if-addr<"
0xe/imm32/size
0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/<
2020-05-17 18:24:40 +00:00
_string-break-if-addr<=: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "break-if-addr<="
0xf/imm32/size
0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< 0x3d/=
2020-05-17 18:24:40 +00:00
_string-break-if-addr>: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "break-if-addr>"
0xe/imm32/size
0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/>
2020-05-17 18:24:40 +00:00
_string-break-if-addr>=: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "break-if-addr>="
0xf/imm32/size
0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> 0x3d/=
2020-05-17 18:24:40 +00:00
_string-compare: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "compare"
0x7/imm32/size
0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e
2020-05-17 18:24:40 +00:00
_string-copy: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "copy"
0x4/imm32/size
0x63/c 0x6f/o 0x70/p 0x79/y
2020-05-17 18:24:40 +00:00
_string-copy-to: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "copy-to"
0x7/imm32/size
0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o
2020-05-17 18:24:40 +00:00
_string-decrement: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "decrement"
0x9/imm32/size
0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
2020-05-17 18:24:40 +00:00
_string-increment: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "increment"
0x9/imm32/size
0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
2020-05-17 18:24:40 +00:00
_string-loop: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "loop"
0x4/imm32/size
0x6c/l 0x6f/o 0x6f/o 0x70/p
2020-05-17 18:24:40 +00:00
_string-loop-if-<: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "loop-if-<"
0x9/imm32/size
0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
2020-05-17 18:24:40 +00:00
_string-loop-if-<=: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "loop-if-<="
0xa/imm32/size
0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
2020-05-17 18:24:40 +00:00
_string-loop-if-=: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "loop-if-="
0x9/imm32/size
0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
2020-05-17 18:24:40 +00:00
_string-loop-if->: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "loop-if->"
0x9/imm32/size
0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
2020-05-17 18:24:40 +00:00
_string-loop-if->=: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "loop-if->="
0xa/imm32/size
0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
2020-05-17 18:24:40 +00:00
_string-loop-if-!=: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "loop-if-!="
0xa/imm32/size
0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
2020-05-17 18:24:40 +00:00
_string-loop-if-addr<: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "loop-if-addr<"
0xd/imm32/size
0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/<
2020-05-17 18:24:40 +00:00
_string-loop-if-addr<=: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "loop-if-addr<="
0xe/imm32/size
0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< 0x3d/=
2020-05-17 18:24:40 +00:00
_string-loop-if-addr>: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "loop-if-addr>"
0xd/imm32/size
0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/>
2020-05-17 18:24:40 +00:00
_string-loop-if-addr>=: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "loop-if-addr>="
0xe/imm32/size
0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> 0x3d/=
2020-05-17 18:24:40 +00:00
_string-multiply: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "multiply"
0x8/imm32/size
0x6d/m 0x75/u 0x6c/l 0x74/t 0x69/i 0x70/p 0x6c/l 0x79/y
2020-05-17 18:24:40 +00:00
_string-or: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "or"
0x2/imm32/size
0x6f/o 0x72/r
2020-05-17 18:24:40 +00:00
_string-or-with: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "or-with"
0x7/imm32/size
0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
2020-05-17 18:24:40 +00:00
_string-subtract: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "subtract"
0x8/imm32/size
0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
2020-05-17 18:24:40 +00:00
_string-subtract-from: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "subtract-from"
0xd/imm32/size
0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t 0x2d/dash 0x66/f 0x72/r 0x6f/o 0x6d/m
2020-05-17 18:24:40 +00:00
_string-xor: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "xor"
0x3/imm32/size
0x78/x 0x6f/o 0x72/r
2020-05-17 18:24:40 +00:00
_string-xor-with: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "xor-with"
0x8/imm32/size
0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
# string literals for SubX instructions
2020-05-17 18:24:40 +00:00
_string_01_add_to: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "01/add-to"
0x9/imm32/size
0x30/0 0x31/1 0x2f/slash 0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
2020-05-17 18:24:40 +00:00
_string_03_add: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "03/add"
0x6/imm32/size
0x30/0 0x33/3 0x2f/slash 0x61/a 0x64/d 0x64/d
2020-05-17 18:24:40 +00:00
_string_05_add_to_eax: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "05/add-to-eax"
0xd/imm32/size
0x30/0 0x35/5 0x2f/slash 0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x65/e 0x61/a 0x78/x
2020-05-17 18:24:40 +00:00
_string_09_or_with: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "09/or-with"
0xa/imm32/size
0x30/0 0x39/9 0x2f/slash 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
2020-05-17 18:24:40 +00:00
_string_0b_or: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0b/or"
0x5/imm32/size
0x30/0 0x62/b 0x2f/slash 0x6f/o 0x72/r
2020-05-17 18:24:40 +00:00
_string_0d_or_with_eax: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0d/or-with-eax"
0xe/imm32/size
0x30/0 0x64/d 0x2f/slash 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h 0x2d/dash 0x65/e 0x61/a 0x78/x
2020-05-17 18:24:40 +00:00
_string_0f_82_jump_label: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 82/jump-if-addr<"
0x13/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x32/2 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/<
2020-05-17 18:24:40 +00:00
_string_0f_82_jump_break: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 82/jump-if-addr< break/disp32"
0x20/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x32/2 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
2020-05-17 18:24:40 +00:00
_string_0f_82_jump_loop: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 82/jump-if-addr< loop/disp32"
0x1f/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x32/2 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
2020-05-17 18:24:40 +00:00
_string_0f_83_jump_label: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 83/jump-if-addr>="
0x14/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x33/3 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> 0x3d/=
2020-05-17 18:24:40 +00:00
_string_0f_83_jump_break: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 83/jump-if-addr>= break/disp32"
0x21/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x33/3 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> 0x3d/= 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
2020-05-17 18:24:40 +00:00
_string_0f_83_jump_loop: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 83/jump-if-addr>= loop/disp32"
0x20/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x33/3 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> 0x3d/= 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
2020-05-17 18:24:40 +00:00
_string_0f_84_jump_label: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 84/jump-if-="
0xf/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x34/4 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
2020-05-17 18:24:40 +00:00
_string_0f_84_jump_break: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 84/jump-if-= break/disp32"
0x1c/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x34/4 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/= 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
2020-05-17 18:24:40 +00:00
_string_0f_84_jump_loop: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 84/jump-if-= loop/disp32"
0x1b/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x34/4 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/= 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
2020-05-17 18:24:40 +00:00
_string_0f_85_jump_label: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 85/jump-if-!="
0x10/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x35/5 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
2020-05-17 18:24:40 +00:00
_string_0f_85_jump_break: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 85/jump-if-!= break/disp32"
0x1d/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x35/5 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/= 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
2020-05-17 18:24:40 +00:00
_string_0f_85_jump_loop: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 85/jump-if-!= loop/disp32"
0x1c/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x35/5 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/= 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
2020-05-17 18:24:40 +00:00
_string_0f_86_jump_label: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 86/jump-if-addr<="
0x14/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x36/6 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< 0x3d/=
2020-05-17 18:24:40 +00:00
_string_0f_86_jump_break: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 86/jump-if-addr<= break/disp32"
0x21/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x36/6 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< 0x3d/= 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
2020-05-17 18:24:40 +00:00
_string_0f_86_jump_loop: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 86/jump-if-addr<= loop/disp32"
0x20/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x36/6 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< 0x3d/= 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
2020-05-17 18:24:40 +00:00
_string_0f_87_jump_label: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 87/jump-if-addr>"
0x13/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x37/7 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/>
2020-05-17 18:24:40 +00:00
_string_0f_87_jump_break: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 87/jump-if-addr> break/disp32"
0x20/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x37/7 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
2020-05-17 18:24:40 +00:00
_string_0f_87_jump_loop: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 87/jump-if-addr> loop/disp32"
0x1f/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x37/7 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
2020-05-17 18:24:40 +00:00
_string_0f_8c_jump_label: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 8c/jump-if-<"
0xf/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x63/c 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
2020-05-17 18:24:40 +00:00
_string_0f_8c_jump_break: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 8c/jump-if-< break/disp32"
0x1c/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x63/c 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
2020-05-17 18:24:40 +00:00
_string_0f_8c_jump_loop: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 8c/jump-if-< loop/disp32"
0x1b/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x63/c 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
2020-05-17 18:24:40 +00:00
_string_0f_8d_jump_label: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 8d/jump-if->="
0x10/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x64/d 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
2020-05-17 18:24:40 +00:00
_string_0f_8d_jump_break: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 8d/jump-if->= break/disp32"
0x1d/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x64/d 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/= 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
2020-05-17 18:24:40 +00:00
_string_0f_8d_jump_loop: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 8d/jump-if->= loop/disp32"
0x1c/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x64/d 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/= 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
2020-05-17 18:24:40 +00:00
_string_0f_8e_jump_label: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 8e/jump-if-<="
0x10/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x65/e 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
2020-05-17 18:24:40 +00:00
_string_0f_8e_jump_break: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 8e/jump-if-<= break/disp32"
0x1d/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x65/e 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/= 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
2020-05-17 18:24:40 +00:00
_string_0f_8e_jump_loop: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 8e/jump-if-<= loop/disp32"
0x1c/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x65/e 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/= 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
2020-05-17 18:24:40 +00:00
_string_0f_8f_jump_label: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 8f/jump-if->"
0xf/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x66/f 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
2020-05-17 18:24:40 +00:00
_string_0f_8f_jump_break: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 8f/jump-if-> break/disp32"
0x1c/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x66/f 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
2020-05-17 18:24:40 +00:00
_string_0f_8f_jump_loop: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f 8f/jump-if-> loop/disp32"
0x1b/imm32/size
0x30/0 0x66/f 0x20/space 0x38/8 0x66/f 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
2020-05-17 18:24:40 +00:00
_string_0f_af_multiply: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "0f af/multiply"
0xe/imm32/size
0x30/0 0x66/f 0x20/space 0x61/a 0x66/f 0x2f/slash 0x6d/m 0x75/u 0x6c/l 0x74/t 0x69/i 0x70/p 0x6c/l 0x79/y
2020-05-17 18:24:40 +00:00
_string_21_and_with: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "21/and-with"
0xb/imm32/size
0x32/2 0x31/1 0x2f/slash 0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
2020-05-17 18:24:40 +00:00
_string_23_and: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "23/and"
0x6/imm32/size
0x32/2 0x33/3 0x2f/slash 0x61/a 0x6e/n 0x64/d
2020-05-17 18:24:40 +00:00
_string_25_and_with_eax: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "25/and-with-eax"
0xf/imm32/size
0x32/2 0x35/5 0x2f/slash 0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h 0x2d/dash 0x65/e 0x61/a 0x78/x
2020-05-17 18:24:40 +00:00
_string_29_subtract_from: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "29/subtract-from"
0x10/imm32/size
0x32/2 0x39/9 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t 0x2d/dash 0x66/f 0x72/r 0x6f/o 0x6d/m
2020-05-17 18:24:40 +00:00
_string_2b_subtract: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "2b/subtract"
0xb/imm32/size
0x32/2 0x62/b 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
2020-05-17 18:24:40 +00:00
_string_2d_subtract_from_eax: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "2d/subtract-from-eax"
0x14/imm32/size
0x32/2 0x64/d 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t 0x2d/dash 0x66/f 0x72/r 0x6f/o 0x6d/m 0x2d/dash 0x65/e 0x61/a 0x78/x
2020-05-17 18:24:40 +00:00
_string_31_xor_with: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "31/xor-with"
0xb/imm32/size
0x33/3 0x31/1 0x2f/slash 0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
2020-05-17 18:24:40 +00:00
_string_33_xor: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "33/xor"
0x6/imm32/size
0x33/3 0x33/3 0x2f/slash 0x78/x 0x6f/o 0x72/r
2020-05-17 18:24:40 +00:00
_string_35_xor_with_eax: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "35/xor-with-eax"
0xf/imm32/size
0x33/3 0x35/5 0x2f/slash 0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h 0x2d/dash 0x65/e 0x61/a 0x78/x
2020-05-17 18:24:40 +00:00
_string_39_compare->: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "39/compare->"
0xc/imm32/size
0x33/3 0x39/9 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x2d/dash 0x3e/>
2020-05-17 18:24:40 +00:00
_string_3b_compare<-: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "3b/compare<-"
0xc/imm32/size
0x33/3 0x62/b 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x3c/< 0x2d/dash
2020-05-17 18:24:40 +00:00
_string_3d_compare_eax_with: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "3d/compare-eax-with"
0x13/imm32/size
0x33/3 0x64/d 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x2d/dash 0x65/e 0x61/a 0x78/x 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
2020-05-17 18:24:40 +00:00
_string_40_increment_eax: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "40/increment-eax"
0x10/imm32/size
0x34/4 0x30/0 0x2f/slash 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x61/a 0x78/x
2020-05-17 18:24:40 +00:00
_string_41_increment_ecx: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "41/increment-ecx"
0x10/imm32/size
0x34/4 0x31/1 0x2f/slash 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x63/c 0x78/x
2020-05-17 18:24:40 +00:00
_string_42_increment_edx: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "42/increment-edx"
0x10/imm32/size
0x34/4 0x32/2 0x2f/slash 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x64/d 0x78/x
2020-05-17 18:24:40 +00:00
_string_43_increment_ebx: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "43/increment-ebx"
0x10/imm32/size
0x34/4 0x33/3 0x2f/slash 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x62/b 0x78/x
2020-05-17 18:24:40 +00:00
_string_46_increment_esi: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "46/increment-esi"
0x10/imm32/size
0x34/4 0x36/6 0x2f/slash 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x73/s 0x69/i
2020-05-17 18:24:40 +00:00
_string_47_increment_edi: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "47/increment-edi"
0x10/imm32/size
0x34/4 0x37/7 0x2f/slash 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x64/d 0x69/i
2020-05-17 18:24:40 +00:00
_string_48_decrement_eax: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "48/decrement-eax"
0x10/imm32/size
0x34/4 0x38/8 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x61/a 0x78/x
2020-05-17 18:24:40 +00:00
_string_49_decrement_ecx: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "49/decrement-ecx"
0x10/imm32/size
0x34/4 0x39/9 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x63/c 0x78/x
2020-05-17 18:24:40 +00:00
_string_4a_decrement_edx: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "4a/decrement-edx"
0x10/imm32/size
0x34/4 0x61/a 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x64/d 0x78/x
2020-05-17 18:24:40 +00:00
_string_4b_decrement_ebx: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "4b/decrement-ebx"
0x10/imm32/size
0x34/4 0x62/b 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x62/b 0x78/x
2020-05-17 18:24:40 +00:00
_string_4e_decrement_esi: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "4e/decrement-esi"
0x10/imm32/size
0x34/4 0x65/e 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x73/s 0x69/i
2020-05-17 18:24:40 +00:00
_string_4f_decrement_edi: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "4f/decrement-edi"
0x10/imm32/size
0x34/4 0x66/f 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x64/d 0x69/i
2020-05-17 18:24:40 +00:00
_string_81_subop_add: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "81 0/subop/add"
0xe/imm32/size
0x38/8 0x31/1 0x20/space 0x30/0 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x61/a 0x64/d 0x64/d
2020-05-17 18:24:40 +00:00
_string_81_subop_or: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "81 1/subop/or"
0xd/imm32/size
0x38/8 0x31/1 0x20/space 0x31/1 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x6f/o 0x72/r
2020-05-17 18:24:40 +00:00
_string_81_subop_and: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "81 4/subop/and"
0xe/imm32/size
0x38/8 0x31/1 0x20/space 0x34/4 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x61/a 0x6e/n 0x64/d
2020-05-17 18:24:40 +00:00
_string_81_subop_subtract: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "81 5/subop/subtract"
0x13/imm32/size
0x38/8 0x31/1 0x20/space 0x35/5 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
2020-05-17 18:24:40 +00:00
_string_81_subop_xor: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "81 6/subop/xor"
0xe/imm32/size
0x38/8 0x31/1 0x20/space 0x36/6 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x78/x 0x6f/o 0x72/r
2020-05-17 18:24:40 +00:00
_string_81_subop_compare: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "81 7/subop/compare"
0x12/imm32/size
0x38/8 0x31/1 0x20/space 0x37/7 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e
2020-05-17 18:24:40 +00:00
_string_89_<-: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "89/<-"
0x5/imm32/size
0x38/8 0x39/9 0x2f/slash 0x3c/< 0x2d/dash
2020-05-17 18:24:40 +00:00
_string_8b_->: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "8b/->"
0x5/imm32/size
0x38/8 0x62/b 0x2f/slash 0x2d/dash 0x3e/>
2020-05-17 18:24:40 +00:00
_string_8d_copy_address: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "8d/copy-address"
0xf/imm32/size
0x38/8 0x64/d 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x65/e 0x73/s 0x73/s
2020-05-17 18:24:40 +00:00
_string_b8_copy_to_eax: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "b8/copy-to-eax"
0xe/imm32/size
0x62/b 0x38/8 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x65/e 0x61/a 0x78/x
2020-05-17 18:24:40 +00:00
_string_b9_copy_to_ecx: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "b9/copy-to-ecx"
0xe/imm32/size
0x62/b 0x39/9 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x65/e 0x63/c 0x78/x
2020-05-17 18:24:40 +00:00
_string_ba_copy_to_edx: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "ba/copy-to-edx"
0xe/imm32/size
0x62/b 0x61/a 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x65/e 0x64/d 0x78/x
2020-05-17 18:24:40 +00:00
_string_bb_copy_to_ebx: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "bb/copy-to-ebx"
0xe/imm32/size
0x62/b 0x62/b 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x65/e 0x62/b 0x78/x
2020-05-17 18:24:40 +00:00
_string_be_copy_to_esi: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "be/copy-to-esi"
0xe/imm32/size
0x62/b 0x65/e 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x65/e 0x73/s 0x69/i
2020-05-17 18:24:40 +00:00
_string_bf_copy_to_edi: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "bf/copy-to-edi"
0xe/imm32/size
0x62/b 0x66/f 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x65/e 0x64/d 0x69/i
2020-05-17 18:24:40 +00:00
_string_c7_subop_copy: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "c7 0/subop/copy"
0xf/imm32/size
0x63/c 0x37/7 0x20/space 0x30/0 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y
2020-05-17 18:24:40 +00:00
_string_e9_jump_label: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "e9/jump"
0x7/imm32/size
0x65/e 0x39/9 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p
2020-05-17 18:24:40 +00:00
_string_e9_jump_break: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "e9/jump break/disp32"
0x14/imm32/size
0x65/e 0x39/9 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
2020-05-17 18:24:40 +00:00
_string_e9_jump_loop: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "e9/jump loop/disp32"
0x13/imm32/size
0x65/e 0x39/9 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
2020-05-17 18:24:40 +00:00
_string_ff_subop_increment: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
# "ff 0/subop/increment"
0x14/imm32/size
2020-05-18 02:34:30 +00:00
0x66/f 0x66/f 0x20/space 0x30/0 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
2020-05-17 18:24:40 +00:00
_string_ff_subop_decrement: # (payload array byte)
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
2020-05-17 18:24:40 +00:00
Single-int-var-in-mem: # (payload list var)
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
Int-var-in-mem/imm32
0/imm32/next
0/imm32/next
2020-05-17 18:24:40 +00:00
Int-var-in-mem: # (payload var)
0x11/imm32/alloc-id:fake:payload
0/imm32/name
0/imm32/name
0x11/imm32/alloc-id:fake
2020-01-13 04:25:11 +00:00
Type-int/imm32
1/imm32/some-block-depth
1/imm32/some-stack-offset
0/imm32/no-register
0/imm32/no-register
2020-05-17 18:24:40 +00:00
Two-args-int-stack-int-reg: # (payload list var)
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
Int-var-in-mem/imm32
0x11/imm32/alloc-id:fake
2019-11-27 02:07:55 +00:00
Single-int-var-in-some-register/imm32/next
2019-11-27 01:41:25 +00:00
2020-05-17 18:24:40 +00:00
Two-args-int-reg-int-stack: # (payload list var)
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
2020-01-30 03:43:20 +00:00
Int-var-in-some-register/imm32
0x11/imm32/alloc-id:fake
Single-int-var-in-mem/imm32/next
2020-01-30 03:43:20 +00:00
2020-05-17 18:24:40 +00:00
Two-args-int-eax-int-literal: # (payload list var)
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
2020-01-30 03:43:20 +00:00
Int-var-in-eax/imm32
0x11/imm32/alloc-id:fake
2020-01-30 03:43:20 +00:00
Single-lit-var/imm32/next
2020-05-17 18:24:40 +00:00
Int-var-and-literal: # (payload list var)
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
Int-var-in-mem/imm32
0x11/imm32/alloc-id:fake
2019-11-27 01:41:25 +00:00
Single-lit-var/imm32/next
2020-05-17 18:24:40 +00:00
Int-var-in-register-and-literal: # (payload list var)
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
Int-var-in-some-register/imm32
0x11/imm32/alloc-id:fake
Single-lit-var/imm32/next
2020-05-17 18:24:40 +00:00
Single-int-var-in-some-register: # (payload list var)
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
Int-var-in-some-register/imm32
2020-05-17 17:16:19 +00:00
0/imm32/next
0/imm32/next
2020-05-17 18:24:40 +00:00
Single-addr-var-in-some-register: # (payload list var)
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
Addr-var-in-some-register/imm32
2020-05-17 17:16:19 +00:00
0/imm32/next
0/imm32/next
2020-05-17 23:31:58 +00:00
Int-var-in-some-register: # (payload var)
0x11/imm32/alloc-id:fake:payload
0/imm32/name
0/imm32/name
0x11/imm32/alloc-id:fake
2020-01-13 04:25:11 +00:00
Type-int/imm32
1/imm32/some-block-depth
2019-11-27 01:41:25 +00:00
0/imm32/no-stack-offset
0x11/imm32/alloc-id:fake
2020-02-20 08:22:11 +00:00
Any-register/imm32
2020-05-17 23:31:58 +00:00
Any-register: # (payload array byte)
0x11/imm32/alloc-id:fake:payload
1/imm32/size
# data
2a/asterisk
Addr-var-in-some-register: # (payload var)
0x11/imm32/alloc-id:fake:payload
0/imm32/name
0/imm32/name
0x11/imm32/alloc-id:fake
Type-addr/imm32
1/imm32/some-block-depth
0/imm32/no-stack-offset
0x11/imm32/alloc-id:fake
Any-register/imm32
2020-05-17 18:24:40 +00:00
Single-int-var-in-eax: # (payload list var)
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
Int-var-in-eax/imm32
0/imm32/next
0/imm32/next
Int-var-in-eax:
0x11/imm32/alloc-id:fake:payload
0/imm32/name
0/imm32/name
0x11/imm32/alloc-id:fake
2020-01-13 04:25:11 +00:00
Type-int/imm32
1/imm32/some-block-depth
0/imm32/no-stack-offset
0x11/imm32/alloc-id:fake
$Register-eax/imm32
2020-05-17 18:24:40 +00:00
Single-int-var-in-ecx: # (payload list var)
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
Int-var-in-ecx/imm32
2020-05-17 17:16:19 +00:00
0/imm32/next
0/imm32/next
Int-var-in-ecx:
0x11/imm32/alloc-id:fake:payload
0/imm32/name
0/imm32/name
0x11/imm32/alloc-id:fake
2020-01-13 04:25:11 +00:00
Type-int/imm32
1/imm32/some-block-depth
0/imm32/no-stack-offset
0x11/imm32/alloc-id:fake
$Register-ecx/imm32/register
2020-05-17 18:24:40 +00:00
Single-int-var-in-edx: # (payload list var)
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
Int-var-in-edx/imm32
2020-05-17 17:16:19 +00:00
0/imm32/next
0/imm32/next
2020-05-17 18:24:40 +00:00
Int-var-in-edx: # (payload list var)
0x11/imm32/alloc-id:fake:payload
0/imm32/name
0/imm32/name
0x11/imm32/alloc-id:fake
2020-01-13 04:25:11 +00:00
Type-int/imm32
1/imm32/some-block-depth
0/imm32/no-stack-offset
0x11/imm32/alloc-id:fake
$Register-edx/imm32/register
2020-05-17 18:24:40 +00:00
Single-int-var-in-ebx: # (payload list var)
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
Int-var-in-ebx/imm32
2020-05-17 17:16:19 +00:00
0/imm32/next
0/imm32/next
2020-05-17 18:24:40 +00:00
Int-var-in-ebx: # (payload list var)
0x11/imm32/alloc-id:fake:payload
0/imm32/name
0/imm32/name
0x11/imm32/alloc-id:fake
2020-01-13 04:25:11 +00:00
Type-int/imm32
1/imm32/some-block-depth
0/imm32/no-stack-offset
0x11/imm32/alloc-id:fake
$Register-ebx/imm32/register
2020-05-17 18:24:40 +00:00
Single-int-var-in-esi: # (payload list var)
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
Int-var-in-esi/imm32
2020-05-17 17:16:19 +00:00
0/imm32/next
0/imm32/next
2020-05-17 18:24:40 +00:00
Int-var-in-esi: # (payload list var)
0x11/imm32/alloc-id:fake:payload
0/imm32/name
0/imm32/name
0x11/imm32/alloc-id:fake
2020-01-13 04:25:11 +00:00
Type-int/imm32
1/imm32/some-block-depth
0/imm32/no-stack-offset
0x11/imm32/alloc-id:fake
$Register-esi/imm32/register
2020-05-17 18:24:40 +00:00
Single-int-var-in-edi: # (payload list var)
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
Int-var-in-edi/imm32
2020-05-17 17:16:19 +00:00
0/imm32/next
0/imm32/next
2020-05-17 18:24:40 +00:00
Int-var-in-edi: # (payload list var)
0x11/imm32/alloc-id:fake:payload
0/imm32/name
0/imm32/name
0x11/imm32/alloc-id:fake
2020-01-13 04:25:11 +00:00
Type-int/imm32
1/imm32/some-block-depth
0/imm32/no-stack-offset
0x11/imm32/alloc-id:fake
$Register-edi/imm32/register
2020-05-17 18:24:40 +00:00
Single-lit-var: # (payload list var)
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
Lit-var/imm32
2020-05-17 17:16:19 +00:00
0/imm32/next
0/imm32/next
2020-05-17 18:24:40 +00:00
Lit-var: # (payload var)
0x11/imm32/alloc-id:fake:payload
0/imm32/name
0/imm32/name
0x11/imm32/alloc-id:fake
2020-01-13 04:25:11 +00:00
Type-literal/imm32
1/imm32/some-block-depth
0/imm32/no-stack-offset
0/imm32/no-register
0/imm32/no-register
2020-05-17 18:24:40 +00:00
Type-int: # (payload tree type-id)
0x11/imm32/alloc-id:fake:payload
2020-04-12 09:33:01 +00:00
1/imm32/left-is-atom
1/imm32/value:int
0/imm32/left:unused
0/imm32/right:null
0/imm32/right:null
2020-01-13 04:25:11 +00:00
2020-05-17 18:24:40 +00:00
Type-literal: # (payload tree type-id)
2020-05-17 17:16:19 +00:00
0x11/imm32/alloc-id:fake:payload
1/imm32/is-atom
0/imm32/value:literal
0/imm32/left:unused
0/imm32/right:null
0/imm32/right:null
2020-01-13 04:25:11 +00:00
2020-05-17 18:24:40 +00:00
Type-addr: # (payload tree type-id)
2020-05-17 17:16:19 +00:00
0x11/imm32/alloc-id:fake:payload
1/imm32/is-atom
2/imm32/value:addr
0/imm32/left:unused
0/imm32/right:null
0/imm32/right:null
== code
2020-05-13 07:51:31 +00:00
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)
2020-05-13 07:51:31 +00:00
(lookup *(ecx+0x18) *(ecx+0x1c)) # Primitive-subx-name Primitive-subx-name => eax
(write-buffered *(ebp+8) %eax)
# emit rm32 if necessary
2020-05-13 07:51:31 +00:00
(emit-subx-rm32 *(ebp+8) *(ecx+0x20) *(ebp+0xc)) # out, Primitive-subx-rm32, stmt
# emit r32 if necessary
2020-05-13 07:51:31 +00:00
(emit-subx-r32 *(ebp+8) *(ecx+0x24) *(ebp+0xc)) # out, Primitive-subx-r32, stmt
# emit imm32 if necessary
2020-05-13 07:51:31 +00:00
(emit-subx-imm32 *(ebp+8) *(ecx+0x28) *(ebp+0xc)) # out, Primitive-subx-imm32, stmt
2020-01-30 01:34:07 +00:00
# emit disp32 if necessary
2020-05-13 07:51:31 +00:00
(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
2020-05-20 19:35:39 +00:00
# var v/eax: (addr stmt-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
2020-02-21 00:23:06 +00:00
# if (l == 1) return stmt->inouts
{
3d/compare-eax-and 1/imm32
75/jump-if-!= break/disp8
$get-stmt-operand-from-arg-location:1:
2020-05-13 07:51:31 +00:00
(lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax
eb/jump $get-stmt-operand-from-arg-location:end/disp8
}
2020-02-21 00:23:06 +00:00
# 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:
2020-05-13 07:51:31 +00:00
(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:
2020-05-13 07:51:31 +00:00
(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)
2020-01-27 09:45:08 +00:00
(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
2020-05-17 17:16:19 +00:00
# if (l == 0) return
81 7/subop/compare *(ebp+0xc) 0/imm32
0f 84/jump-if-= $emit-subx-r32:end/disp32
2020-05-20 19:35:39 +00:00
# var v/eax: (addr stmt-var)
2020-02-21 00:23:06 +00:00
(get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # => eax
2020-05-17 17:16:19 +00:00
(lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax
(lookup *(eax+0x18) *(eax+0x1c)) # Var-register Var-register => eax
(maybe-get Registers %eax 0xc) # => 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
2020-05-17 17:16:19 +00:00
# if (l == 0) return
81 7/subop/compare *(ebp+0xc) 0/imm32
2020-05-17 22:54:47 +00:00
0f 84/jump-if-= $emit-subx-imm32:end/disp32
2020-02-21 00:23:06 +00:00
# var v/eax: (handle var)
(get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # => eax
2020-05-17 22:54:47 +00:00
(lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax
(lookup *eax *(eax+4)) # Var-name Var-name => eax
(write-buffered *(ebp+8) Space)
2020-05-17 22:54:47 +00:00
(write-buffered *(ebp+8) %eax)
(write-buffered *(ebp+8) "/imm32")
$emit-subx-imm32:end:
# . restore registers
59/pop-to-ecx
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
emit-subx-disp32: # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
2020-01-30 01:34:07 +00:00
# . 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
2020-05-20 19:35:39 +00:00
# var v/eax: (addr stmt-var)
2020-02-21 00:23:06 +00:00
(get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # => eax
2020-05-20 19:35:39 +00:00
(lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax
(lookup *eax *(eax+4)) # Var-name Var-name => eax
2020-01-30 01:34:07 +00:00
(write-buffered *(ebp+8) Space)
2020-05-20 19:35:39 +00:00
(write-buffered *(ebp+8) %eax)
2020-01-30 01:34:07 +00:00
# hack: if instruction operation starts with "break", emit ":break"
2020-05-20 19:35:39 +00:00
# var name/ecx: (addr array byte) = lookup(stmt->operation)
2020-01-30 01:34:07 +00:00
8b/-> *(ebp+0x10) 0/r32/eax
2020-05-20 19:35:39 +00:00
(lookup *(eax+4) *(eax+8)) # Stmt1-operation Stmt1-operation => eax
89/<- %ecx 0/r32/eax
2020-01-30 01:34:07 +00:00
{
(string-starts-with? %ecx "break") # => eax
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
2020-01-30 01:34:07 +00:00
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
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
2020-01-30 01:34:07 +00:00
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
2020-05-13 07:51:31 +00:00
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
2020-05-13 07:51:31 +00:00
(lookup *(ecx+4) *(ecx+8)) # Stmt1-operation Stmt1-operation => eax
(write-buffered *(ebp+8) %eax)
# - emit arguments
# var curr/eax: (addr stmt-var) = lookup(stmt->inouts)
2020-05-13 07:51:31 +00:00
(lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax
{
# if (curr == null) break
3d/compare-eax-and 0/imm32
74/jump-if-= break/disp8
#
(emit-subx-call-operand *(ebp+8) %eax)
# curr = lookup(curr->next)
(lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax
eb/jump loop/disp8
}
#
(write-buffered *(ebp+8) ")\n")
$emit-call:end:
# . restore registers
59/pop-to-ecx
2020-05-13 07:51:31 +00:00
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)
2020-01-27 22:18:34 +00:00
# shares code with emit-subx-var-as-rm32
2019-11-19 01:36:59 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
51/push-ecx
2020-02-21 01:51:49 +00:00
56/push-esi
# ecx = s
8b/-> *(ebp+0xc) 1/r32/ecx
2020-05-13 07:51:31 +00:00
# var operand/esi: (addr var) = lookup(s->value)
(lookup *ecx *(ecx+4)) # Stmt-var-value Stmt-var-value => eax
89/<- %esi 0/r32/eax
2020-03-14 22:15:46 +00:00
# if (operand->register && !s->is-deref?) emit "%__"
{
2020-03-14 22:15:46 +00:00
$emit-subx-call-operand:check-for-register-direct:
2020-05-13 07:51:31 +00:00
81 7/subop/compare *(esi+0x18) 0/imm32 # Var-register
74/jump-if-= break/disp8
2020-05-13 07:51:31 +00:00
81 7/subop/compare *(ecx+0x10) 0/imm32/false # Stmt-var-is-deref
2020-03-14 22:15:46 +00:00
75/jump-if-!= break/disp8
$emit-subx-call-operand:register-direct:
(write-buffered *(ebp+8) " %")
2020-05-13 07:51:31 +00:00
(lookup *(esi+0x18) *(esi+0x1c)) # Var-register Var-register => eax
(write-buffered *(ebp+8) %eax)
e9/jump $emit-subx-call-operand:end/disp32
}
2020-03-14 22:15:46 +00:00
# else if (operand->register && s->is-deref?) emit "*__"
2020-01-13 04:25:11 +00:00
{
2020-03-14 22:15:46 +00:00
$emit-subx-call-operand:check-for-register-indirect:
2020-05-13 07:51:31 +00:00
81 7/subop/compare *(esi+0x18) 0/imm32 # Var-register
74/jump-if-= break/disp8
2020-05-13 07:51:31 +00:00
81 7/subop/compare *(ecx+0x10) 0/imm32/false # Stmt-var-is-deref
2020-03-14 22:15:46 +00:00
74/jump-if-= break/disp8
$emit-subx-call-operand:register-indirect:
2020-03-14 22:19:12 +00:00
(emit-subx-call-operand-register-indirect *(ebp+8) %esi)
2020-01-13 04:25:11 +00:00
e9/jump $emit-subx-call-operand:end/disp32
}
# else if (operand->stack-offset) emit "*(ebp+__)"
{
2020-05-13 07:51:31 +00:00
81 7/subop/compare *(esi+0x14) 0/imm32 # Var-offset
74/jump-if-= break/disp8
2020-01-13 04:25:11 +00:00
$emit-subx-call-operand:stack:
(emit-subx-call-operand-stack *(ebp+8) %esi)
2020-01-13 04:25:11 +00:00
e9/jump $emit-subx-call-operand:end/disp32
}
2019-11-19 01:36:59 +00:00
# else if (operand->type == literal) emit "__"
{
2020-05-13 07:51:31 +00:00
(lookup *(esi+8) *(esi+0xc)) # Var-type Var-type => eax
2020-04-12 09:33:01 +00:00
81 7/subop/compare *(eax+4) 0/imm32 # Tree-left
75/jump-if-!= break/disp8
2019-11-19 01:36:59 +00:00
$emit-subx-call-operand:literal:
(write-buffered *(ebp+8) Space)
(lookup *esi *(esi+4)) # Var-name Var-name => eax
(write-buffered *(ebp+8) %eax)
2019-11-19 01:36:59 +00:00
}
$emit-subx-call-operand:end:
# . restore registers
2020-02-21 01:51:49 +00:00
5e/pop-to-esi
59/pop-to-ecx
2019-11-19 01:36:59 +00:00
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)
2020-03-14 22:19:12 +00:00
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
51/push-ecx
56/push-esi
# esi = v
8b/-> *(ebp+0xc) 6/r32/esi
# var size/ecx: int = size-of-deref(v)
(size-of-deref %esi) # => eax
89/<- %ecx 0/r32/eax
# var reg-name/esi: (addr array byte) = lookup(v->register)
(lookup *(esi+0x18) *(esi+0x1c)) # Var-register Var-register => eax
89/<- %esi 0/r32/eax
2020-03-14 22:19:12 +00:00
# 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)
2020-03-14 22:19:12 +00:00
(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+0x14) 1/r32/ecx # Var-offset
# var max/eax: int = v->offset + size-of(v)
(size-of %esi) # => eax
# TODO: assert size is a multiple of 4
01/add-to %eax 1/r32/ecx
{
$emit-subx-call-operand-stack:loop:
# if (curr >= max) break
39/compare %ecx 0/r32/eax
7d/jump-if->= break/disp8
# emit " *(ebp+" curr ")"
(write-buffered *(ebp+8) " *(ebp+")
(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
2020-02-21 01:51:49 +00:00
56/push-esi
# ecx = s
8b/-> *(ebp+0xc) 1/r32/ecx
2020-05-13 07:51:31 +00:00
# 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:
2020-05-13 07:51:31 +00:00
81 7/subop/compare *(esi+0x18) 0/imm32 # Var-register
74/jump-if-= break/disp8
2020-05-13 07:51:31 +00:00
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) " *")
2020-05-13 07:51:31 +00:00
(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:
2020-05-13 07:51:31 +00:00
81 7/subop/compare *(esi+0x18) 0/imm32 # Var-register
74/jump-if-= break/disp8
2020-05-13 07:51:31 +00:00
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) " %")
2020-05-13 07:51:31 +00:00
(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+__)"
{
2020-05-13 07:51:31 +00:00
81 7/subop/compare *(esi+0x14) 0/imm32 # Var-offset
74/jump-if-= break/disp8
2019-11-19 01:36:59 +00:00
$emit-subx-var-as-rm32:stack:
(write-buffered *(ebp+8) Space)
(write-buffered *(ebp+8) "*(ebp+")
2020-05-13 07:51:31 +00:00
(print-int32-buffered *(ebp+8) *(esi+0x14)) # Var-offset
(write-buffered *(ebp+8) ")")
}
2019-11-19 01:36:59 +00:00
$emit-subx-var-as-rm32:end:
# . restore registers
2020-02-21 01:51:49 +00:00
5e/pop-to-esi
59/pop-to-ecx
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
2020-05-07 06:05:13 +00:00
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
2020-05-07 06:05:13 +00:00
# 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
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
74/jump-if-= break/disp8
89/<- %eax 1/r32/ecx
2019-12-26 08:28:16 +00:00
eb/jump $find-matching-primitive:end/disp8
}
$find-matching-primitive:next-primitive:
# curr = curr->next
2020-05-07 06:05:13 +00:00
(lookup *(ecx+0x34) *(ecx+0x38)) # Primitive-next Primitive-next => eax
89/<- %ecx 0/r32/eax
#
2019-12-26 08:28:16 +00:00
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
2020-05-13 07:51:31 +00:00
# . 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
2020-02-17 23:26:49 +00:00
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
}
2020-05-13 07:51:31 +00:00
# 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:
2019-12-26 08:28:16 +00:00
# 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:
2020-05-16 05:10:46 +00:00
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:
2020-05-13 07:51:31 +00:00
(lookup *edi *(edi+4)) # List-value List-value => eax
(operand-matches-primitive? %esi %eax) # => eax
2020-02-17 23:26:49 +00:00
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
}
2020-05-13 07:51:31 +00:00
$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:
2020-05-13 07:51:31 +00:00
# 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
2020-05-13 07:51:31 +00:00
$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:
2020-05-13 07:51:31 +00:00
(lookup *edi *(edi+4)) # List-value List-value => eax
(operand-matches-primitive? %esi %eax) # => eax
2020-02-17 23:26:49 +00:00
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
}
2020-05-13 07:51:31 +00:00
$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
2020-05-13 07:51:31 +00:00
52/push-edx
53/push-ebx
56/push-esi
57/push-edi
# ecx = s
8b/-> *(ebp+8) 1/r32/ecx
2020-05-13 07:51:31 +00:00
# var var/esi: (addr var) = lookup(s->value)
(lookup *ecx *(ecx+4)) # Stmt-var-value Stmt-var-value => eax
89/<- %esi 0/r32/eax
2020-01-01 22:51:07 +00:00
# edi = prim-var
8b/-> *(ebp+0xc) 7/r32/edi
$operand-matches-primitive?:check-type:
2020-01-01 22:51:07 +00:00
# if (var->type != prim-var->type) return false
2020-05-13 07:51:31 +00:00
# . 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
2020-02-17 23:26:49 +00:00
3d/compare-eax-and 0/imm32/false
2020-05-13 07:51:31 +00:00
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
{
2020-05-13 07:51:31 +00:00
81 7/subop/compare *(edi+0x18) 0/imm32 # Var-register
0f 85/jump-if-!= break/disp32
2020-05-13 07:51:31 +00:00
81 7/subop/compare *(esi+0x18) 0/imm32 # Var-register
74/jump-if-= break/disp8
2020-05-13 07:51:31 +00:00
81 7/subop/compare *(ecx+0x10) 0/imm32/false # Stmt-var-is-deref
74/jump-if-= break/disp8
2020-05-17 23:31:58 +00:00
$operand-matches-primitive?:var-deref-match:
e9/jump $operand-matches-primitive?:return-true/disp32
}
# if prim-var is in register and var is in register but dereference, no match
{
2020-05-13 07:51:31 +00:00
81 7/subop/compare *(edi+0x18) 0/imm32 # Var-register
0f 84/jump-if-= break/disp32
2020-05-13 07:51:31 +00:00
81 7/subop/compare *(esi+0x18) 0/imm32 # Var-register
0f 84/jump-if-= break/disp32
2020-05-13 07:51:31 +00:00
81 7/subop/compare *(ecx+0x10) 0/imm32/false # Stmt-var-is-deref
74/jump-if-= break/disp8
2020-05-17 23:31:58 +00:00
$operand-matches-primitive?:var-deref-no-match:
e9/jump $operand-matches-primitive?:return-false/disp32
}
# return false if var->register doesn't match prim-var->register
{
# if register addresses are equal, it's a match
2020-05-13 07:51:31 +00:00
# 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
2020-05-17 23:31:58 +00:00
$operand-matches-primitive?:var-register-no-match:
# if either address is 0, return false
2020-05-13 07:51:31 +00:00
81 7/subop/compare %ebx 0/imm32
74/jump-if-= $operand-matches-primitive?:return-false/disp8
81 7/subop/compare %ecx 0/imm32
2020-02-21 01:55:44 +00:00
74/jump-if-= $operand-matches-primitive?:return-false/disp8
# if prim-var->register is wildcard, it's a match
2020-05-17 23:31:58 +00:00
(string-equal? %ecx "*") # Any-register => eax
3d/compare-eax-and 0/imm32/false
75/jump-if-!= break/disp8
2020-05-17 23:31:58 +00:00
$operand-matches-primitive?:wildcard-no-match:
# if string contents aren't equal, return false
2020-05-13 07:51:31 +00:00
(string-equal? %ecx %ebx) # => eax
2020-05-17 23:59:04 +00:00
3d/compare-eax-and 0/imm32/false
74/jump-if-= $operand-matches-primitive?:return-false/disp8
}
}
$operand-matches-primitive?:return-true:
b8/copy-to-eax 1/imm32/true
2020-02-21 01:55:44 +00:00
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
2020-05-13 07:51:31 +00:00
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
2020-01-13 04:25:11 +00:00
# . 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
2020-03-07 01:41:36 +00:00
81 4/subop/and %eax 0xff/imm32
$subx-type-equal?:end:
2020-01-13 04:25:11 +00:00
# . 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
2020-04-12 09:33:01 +00:00
39/compare *(eax+4) 1/r32/ecx # Tree-value
0f 94/set-byte-if-= %al
2020-03-07 01:41:36 +00:00
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
2020-02-21 23:36:18 +00:00
test-emit-subx-stmt-primitive:
# Primitive operation on a variable on the stack.
2019-11-09 01:31:11 +00:00
# increment foo
# =>
# ff 0/subop/increment *(ebp-8)
#
# There's a variable on the var stack as follows:
2019-11-09 01:31:11 +00:00
# name: 'foo'
# type: int
2019-11-15 01:39:32 +00:00
# stack-offset: -8
2019-11-09 01:31:11 +00:00
#
# There's a primitive with this info:
2019-11-09 01:31:11 +00:00
# name: 'increment'
# inouts: int/mem
2019-11-09 01:31:11 +00:00
# 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)
2020-05-13 07:51:31 +00:00
$test-emit-subx-stmt-primitive:initialize-type:
2020-05-17 22:48:26 +00:00
# var type/ecx: (payload 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
2020-01-13 04:25:11 +00:00
89/<- %ecx 4/r32/esp
2020-05-13 07:51:31 +00:00
$test-emit-subx-stmt-primitive:initialize-var:
2020-05-17 22:48:26 +00:00
# var var-foo/ecx: (payload var) = var(type)
68/push 0/imm32/no-register
68/push 0/imm32/no-register
68/push -8/imm32/stack-offset
68/push 1/imm32/block-depth
51/push-ecx/type
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/name
68/push 0/imm32/name
68/push 0x11/imm32/alloc-id:fake:payload
2019-11-09 01:31:11 +00:00
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:
2020-05-17 22:48:26 +00:00
# var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
68/push 0/imm32/is-deref:false
68/push 0/imm32/next
68/push 0/imm32/next
51/push-ecx/var-foo
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %ebx 4/r32/esp
2020-05-13 07:51:31 +00:00
$test-emit-subx-stmt-primitive:initialize-stmt:
# var stmt/esi: (addr statement)
2020-05-17 01:37:45 +00:00
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
2020-05-13 07:51:31 +00:00
$test-emit-subx-stmt-primitive:initialize-stmt-operation:
# stmt->operation = "increment"
8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation
2020-05-13 07:51:31 +00:00
(copy-array Heap "increment" %eax)
$test-emit-subx-stmt-primitive:initialize-primitive:
# var primitives/ebx: (addr primitive)
2019-11-09 01:31:11 +00:00
68/push 0/imm32/next
2020-05-13 07:51:31 +00:00
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
2020-05-13 07:51:31 +00:00
68/push 0/imm32/subx-name
68/push 0/imm32/subx-name
2020-05-17 01:37:45 +00:00
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
2020-05-13 07:51:31 +00:00
68/push 0/imm32/name
68/push 0/imm32/name
2019-11-09 01:31:11 +00:00
89/<- %ebx 4/r32/esp
2020-05-13 07:51:31 +00:00
$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)
2019-11-09 01:31:11 +00:00
# convert
c7 0/subop/copy *Curr-block-depth 0/imm32
(emit-subx-stmt _test-output-buffered-file %esi %ebx)
2019-11-09 01:31:11 +00:00
(flush _test-output-buffered-file)
#? # dump _test-output-stream {{{
#? (write 2 "^")
#? (write-stream 2 _test-output-stream)
#? (write 2 "$\n")
#? (rewind-stream _test-output-stream)
#? # }}}
# check output
2020-02-21 23:36:18 +00:00
(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
2020-02-21 23:36:18 +00:00
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)
2020-05-13 23:04:17 +00:00
$test-emit-subx-stmt-primitive-register:initialize-type:
2020-05-17 22:48:26 +00:00
# var type/ecx: (payload 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
2020-01-13 04:25:11 +00:00
89/<- %ecx 4/r32/esp
2020-05-13 23:04:17 +00:00
$test-emit-subx-stmt-primitive-register:initialize-var:
2020-05-17 22:48:26 +00:00
# var var-foo/ecx: (payload var)
68/push 0/imm32/register
68/push 0/imm32/register
68/push 0/imm32/no-stack-offset
68/push 1/imm32/block-depth
51/push-ecx
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/name
68/push 0/imm32/name
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %ecx 4/r32/esp
$test-emit-subx-stmt-primitive-register:initialize-var-name:
# var-foo->name = "foo"
8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4
(copy-array Heap "foo" %eax)
$test-emit-subx-stmt-primitive-register:initialize-var-register:
# var-foo->register = "eax"
8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4
2020-05-13 23:04:17 +00:00
(copy-array Heap "eax" %eax)
$test-emit-subx-stmt-primitive-register:initialize-stmt-var:
2020-05-17 22:48:26 +00:00
# var operand/ebx: (payload stmt-var)
68/push 0/imm32/is-deref:false
68/push 0/imm32/next
68/push 0/imm32/next
51/push-ecx/var-foo
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %ebx 4/r32/esp
2020-05-13 23:04:17 +00:00
$test-emit-subx-stmt-primitive-register:initialize-stmt:
# var stmt/esi: (addr statement)
53/push-ebx/outputs
68/push 0x11/imm32/alloc-id:fake
2020-05-17 01:37:45 +00:00
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
2020-05-13 23:04:17 +00:00
$test-emit-subx-stmt-primitive-register:initialize-stmt-operation:
# stmt->operation = "increment"
8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation
2020-05-13 23:04:17 +00:00
(copy-array Heap "increment" %eax)
$test-emit-subx-stmt-primitive-register:initialize-formal-var:
2020-05-17 22:48:26 +00:00
# var formal-var/ebx: (payload var)
68/push 0/imm32/register
68/push 0/imm32/register
68/push 0/imm32/no-stack-offset
68/push 1/imm32/block-depth
ff 6/subop/push *(ecx+0x10) # Var-type + payload alloc id + handle alloc id
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/name
68/push 0/imm32/name
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %ebx 4/r32/esp
$test-emit-subx-stmt-primitive-register:initialize-formal-var-name:
# formal-var->name = "dummy"
8d/copy-address *(ebx+4) 0/r32/eax # Var-name + 4
(copy-array Heap "dummy" %eax)
$test-emit-subx-stmt-primitive-register:initialize-formal-register:
# formal-var->register = "*"
8d/copy-address *(ebx+0x1c) 0/r32/eax # Var-register + 4
(copy-array Heap "*" %eax) # Any-register
2020-05-13 23:04:17 +00:00
$test-emit-subx-stmt-primitive-register:initialize-var-list:
2020-05-17 22:48:26 +00:00
# var formal-outputs/ebx: (payload list var)
68/push 0/imm32/next
68/push 0/imm32/next
53/push-ebx/formal-var
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %ebx 4/r32/esp
2020-05-13 23:04:17 +00:00
$test-emit-subx-stmt-primitive-register:initialize-primitive:
2020-05-17 22:48:26 +00:00
# var primitives/ebx: (addr primitive)
68/push 0/imm32/next
2020-05-13 23:04:17 +00:00
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
2020-05-13 23:04:17 +00:00
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
2020-05-17 01:37:45 +00:00
68/push 0/imm32/no-inouts
68/push 0/imm32/no-inouts
2020-05-13 23:04:17 +00:00
68/push 0/imm32/name
68/push 0/imm32/name
89/<- %ebx 4/r32/esp
2020-05-13 23:04:17 +00:00
$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
2020-02-21 23:36:18 +00:00
(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
2020-02-21 23:36:18 +00:00
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:
2020-05-17 22:48:26 +00:00
# var type/ecx: (payload 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
2020-01-13 04:25:11 +00:00
89/<- %ecx 4/r32/esp
$test-emit-subx-stmt-select-primitive:initialize-var:
2020-05-17 22:48:26 +00:00
# var var-foo/ecx: (payload var)
68/push 0/imm32/register
68/push 0/imm32/register
68/push 0/imm32/no-stack-offset
68/push 1/imm32/block-depth
2020-01-13 04:25:11 +00:00
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:
2020-05-17 22:48:26 +00:00
# var operand/ebx: (payload stmt-var)
68/push 0/imm32/is-deref:false
68/push 0/imm32/next
68/push 0/imm32/next
51/push-ecx/var-foo
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %ebx 4/r32/esp
$test-emit-subx-stmt-select-primitive:initialize-stmt:
# var stmt/esi: (addr statement)
53/push-ebx/outputs
68/push 0x11/imm32/alloc-id:fake
2020-05-17 01:37:45 +00:00
68/push 0/imm32/no-inouts
68/push 0/imm32/no-inouts
68/push 0/imm32/operation
68/push 0/imm32/operation
2019-11-26 05:00:07 +00:00
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:
2020-05-17 22:48:26 +00:00
# var formal-var/ebx: (payload var)
68/push 0/imm32/register
68/push 0/imm32/register
68/push 0/imm32/no-stack-offset
68/push 1/imm32/block-depth
ff 6/subop/push *(ecx+0x10) # Var-type + payload alloc id + handle alloc id
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/name
68/push 0/imm32/name
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %ebx 4/r32/esp
$test-emit-subx-stmt-select-primitive:initialize-formal-var-name:
# formal-var->name = "dummy"
8d/copy-address *(ebx+4) 0/r32/eax # Var-name + 4
(copy-array Heap "dummy" %eax)
$test-emit-subx-stmt-select-primitive:initialize-formal-register:
# formal-var->register = "*"
8d/copy-address *(ebx+0x1c) 0/r32/eax # Var-register + 4
(copy-array Heap "*" %eax) # Any-register
$test-emit-subx-stmt-select-primitive:initialize-var-list:
2020-05-17 22:48:26 +00:00
# var formal-outputs/ebx: (payload list var)
68/push 0/imm32/next
68/push 0/imm32/next
53/push-ebx/formal-var
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %ebx 4/r32/esp
$test-emit-subx-stmt-select-primitive:initialize-primitive2:
2020-05-17 22:48:26 +00:00
# var primitive2/edi: (payload 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
2020-05-17 01:37:45 +00:00
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
2020-05-17 01:37:45 +00:00
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
2020-02-21 23:36:18 +00:00
(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
2020-02-21 23:36:18 +00:00
test-emit-subx-stmt-select-primitive-2:
# Select the right primitive between overloads.
2020-05-16 05:53:15 +00:00
# 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)
2020-05-16 05:53:15 +00:00
$test-emit-subx-stmt-select-primitive-2:initialize-type:
2020-05-17 22:48:26 +00:00
# var type/ecx: (payload tree type-id) = int
2020-05-16 05:53:15 +00:00
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
2020-05-16 05:53:15 +00:00
68/push 0x11/imm32/alloc-id:fake:payload
2020-01-13 04:25:11 +00:00
89/<- %ecx 4/r32/esp
2020-05-16 05:53:15 +00:00
$test-emit-subx-stmt-select-primitive-2:initialize-var:
2020-05-17 22:48:26 +00:00
# var var-foo/ecx: (payload var)
2020-05-16 05:53:15 +00:00
68/push 0/imm32/register
68/push 0/imm32/register
68/push 0/imm32/no-stack-offset
68/push 1/imm32/block-depth
2020-01-13 04:25:11 +00:00
51/push-ecx
2020-05-16 05:53:15 +00:00
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
2020-05-16 05:53:15 +00:00
$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:
2020-05-17 22:48:26 +00:00
# var operand/ebx: (payload stmt-var)
68/push 0/imm32/is-deref:false
68/push 0/imm32/next
68/push 0/imm32/next
2020-05-16 05:53:15 +00:00
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)
2020-05-17 01:37:45 +00:00
68/push 0/imm32/no-outputs
68/push 0/imm32/no-outputs
2020-05-16 05:53:15 +00:00
53/push-ebx/inouts
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/operation
68/push 0/imm32/operation
2019-11-26 05:00:07 +00:00
68/push 1/imm32
89/<- %esi 4/r32/esp
2020-05-16 05:53:15 +00:00
$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:
2020-05-17 22:48:26 +00:00
# var formal-var/ebx: (payload var)
2020-05-16 05:53:15 +00:00
68/push 0/imm32/register
68/push 0/imm32/register
68/push 0/imm32/no-stack-offset
68/push 1/imm32/block-depth
2020-05-16 05:53:15 +00:00
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
2020-05-16 05:53:15 +00:00
$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:
2020-05-17 22:48:26 +00:00
# var formal-outputs/ebx: (payload list stmt-var)
2020-05-16 05:53:15 +00:00
68/push 0/imm32/next
68/push 0/imm32/next
53/push-ebx/formal-var
2020-05-16 05:53:15 +00:00
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %ebx 4/r32/esp
2020-05-16 05:53:15 +00:00
$test-emit-subx-stmt-select-primitive-2:initialize-primitive2:
2020-05-17 22:48:26 +00:00
# var primitive2/edi: (payload primitive)
2020-05-16 05:53:15 +00:00
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
2020-05-16 05:53:15 +00:00
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
2020-05-17 01:37:45 +00:00
68/push 0/imm32/no-inouts
68/push 0/imm32/no-inouts
2020-05-16 05:53:15 +00:00
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
2020-05-16 05:53:15 +00:00
68/push 0/imm32/subx-name
68/push 0/imm32/subx-name
2020-05-17 01:37:45 +00:00
68/push 0/imm32/no-outputs
68/push 0/imm32/no-outputs
2020-05-16 05:53:15 +00:00
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
2020-05-16 05:53:15 +00:00
$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
2020-02-21 23:36:18 +00:00
(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:
2020-02-02 08:05:59 +00:00
# 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:
2020-05-17 22:48:26 +00:00
# var type/ecx: (payload 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
2020-01-13 04:25:11 +00:00
89/<- %ecx 4/r32/esp
$test-increment-register:initialize-var:
2020-05-17 22:48:26 +00:00
# var var-foo/ecx: (payload var)
68/push 0/imm32/register
68/push 0/imm32/register
68/push 0/imm32/no-stack-offset
68/push 1/imm32/block-depth
2020-01-13 04:25:11 +00:00
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:
2020-05-17 22:48:26 +00:00
# var operand/ebx: (payload stmt-var)
68/push 0/imm32/is-deref:false
68/push 0/imm32/next
68/push 0/imm32/next
51/push-ecx/var-foo
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %ebx 4/r32/esp
$test-increment-register:initialize-stmt:
# var stmt/esi: (addr statement)
53/push-ebx/outputs
68/push 0x11/imm32/alloc-id:fake
2020-05-17 01:37:45 +00:00
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)
$test-add-reg-to-reg:initialize-type:
2020-05-17 22:48:26 +00:00
# var type/ecx: (payload 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
2020-01-13 04:25:11 +00:00
89/<- %ecx 4/r32/esp
$test-add-reg-to-reg:initialize-var1:
2020-05-17 22:48:26 +00:00
# var var1/ecx: (payload var)
68/push 0/imm32/register
68/push 0/imm32/register
68/push 0/imm32/no-stack-offset
68/push 1/imm32/block-depth
2020-01-13 04:25:11 +00:00
51/push-ecx
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/name
68/push 0/imm32/name
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %ecx 4/r32/esp
$test-add-reg-to-reg:initialize-var1-name:
# var1->name = "var1"
8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4
(copy-array Heap "var1" %eax)
$test-add-reg-to-reg:initialize-var1-register:
# var1->register = "eax"
8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4
(copy-array Heap "eax" %eax)
$test-add-reg-to-reg:initialize-var2:
2020-05-17 22:48:26 +00:00
# var var2/edx: (payload var)
68/push 0/imm32/register
68/push 0/imm32/register
68/push 0/imm32/no-stack-offset
68/push 1/imm32/block-depth
ff 6/subop/push *(ecx+0x10)
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/name
68/push 0/imm32/name
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %edx 4/r32/esp
$test-add-reg-to-reg:initialize-var2-name:
2020-05-17 18:00:25 +00:00
# var2->name = "var2"
8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4
2020-05-17 18:00:25 +00:00
(copy-array Heap "var2" %eax)
$test-add-reg-to-reg:initialize-var2-register:
2020-05-17 18:00:25 +00:00
# var2->register = "ecx"
8d/copy-address *(edx+0x1c) 0/r32/eax # Var-register + 4
(copy-array Heap "ecx" %eax)
$test-add-reg-to-reg:initialize-inouts:
2020-05-17 22:48:26 +00:00
# var inouts/esi: (payload stmt-var) = [var2]
68/push 0/imm32/is-deref:false
68/push 0/imm32/next
68/push 0/imm32/next
52/push-edx/var2
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %esi 4/r32/esp
$test-add-reg-to-reg:initialize-outputs:
2020-05-17 22:48:26 +00:00
# var outputs/edi: (payload stmt-var) = [var1]
68/push 0/imm32/is-deref:false
68/push 0/imm32/next
68/push 0/imm32/next
51/push-ecx/var1
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %edi 4/r32/esp
$test-add-reg-to-reg:initialize-stmt:
# var stmt/esi: (addr statement)
68/push 0/imm32/next
68/push 0/imm32/next
57/push-edi/outputs
68/push 0x11/imm32/alloc-id:fake
56/push-esi/inouts
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/operation
68/push 0/imm32/operation
68/push 1/imm32/tag:stmt1
89/<- %esi 4/r32/esp
$test-add-reg-to-reg:initialize-stmt-operation:
# stmt->operation = "add"
8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation
(copy-array Heap "add" %eax)
# convert
c7 0/subop/copy *Curr-block-depth 0/imm32
(emit-subx-stmt _test-output-buffered-file %esi Primitives)
(flush _test-output-buffered-file)
#? # dump _test-output-stream {{{
#? (write 2 "^")
#? (write-stream 2 _test-output-stream)
#? (write 2 "$\n")
#? (rewind-stream _test-output-stream)
#? # }}}
# check output
2019-12-26 10:21:55 +00:00
(check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg")
2019-11-09 01:31:11 +00:00
# . 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)
2020-05-17 18:00:25 +00:00
$test-add-reg-to-mem:initialize-type:
2020-05-17 22:48:26 +00:00
# var type/ecx: (payload tree type-id) = int
2020-05-17 18:00:25 +00:00
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
2020-01-13 04:25:11 +00:00
89/<- %ecx 4/r32/esp
2020-05-17 18:00:25 +00:00
$test-add-reg-to-mem:initialize-var1:
2020-05-17 22:48:26 +00:00
# var var1/ecx: (payload var)
2020-05-17 18:00:25 +00:00
68/push 0/imm32/register
68/push 0/imm32/register
68/push 8/imm32/stack-offset
68/push 1/imm32/block-depth
2020-01-13 04:25:11 +00:00
51/push-ecx
2020-05-17 18:00:25 +00:00
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
2020-05-17 18:00:25 +00:00
$test-add-reg-to-mem:initialize-var1-name:
# var1->name = "var1"
8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4
(copy-array Heap "var1" %eax)
$test-add-reg-to-mem:initialize-var2:
2020-05-17 22:48:26 +00:00
# var var2/edx: (payload var)
2020-05-17 18:00:25 +00:00
68/push 0/imm32/register
68/push 0/imm32/register
68/push 0/imm32/no-stack-offset
68/push 1/imm32/block-depth
2020-05-17 18:00:25 +00:00
ff 6/subop/push *(ecx+0x10)
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/name
68/push 0/imm32/name
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %edx 4/r32/esp
2020-05-17 18:00:25 +00:00
$test-add-reg-to-mem:initialize-var2-name:
# var2->name = "var2"
8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4
(copy-array Heap "var2" %eax)
$test-add-reg-to-mem:initialize-var2-register:
# var2->register = "ecx"
8d/copy-address *(edx+0x1c) 0/r32/eax # Var-register + 4
(copy-array Heap "ecx" %eax)
$test-add-reg-to-mem:initialize-inouts:
2020-05-17 22:48:26 +00:00
# var inouts/esi: (payload stmt-var) = [var2]
68/push 0/imm32/is-deref:false
68/push 0/imm32/next
2020-05-17 18:00:25 +00:00
68/push 0/imm32/next
52/push-edx/var2
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %esi 4/r32/esp
2020-05-17 18:00:25 +00:00
# inouts = [var1, var2]
68/push 0/imm32/is-deref:false
56/push-esi/next
2020-05-17 18:00:25 +00:00
68/push 0x11/imm32/alloc-id:fake
51/push-ecx/var1
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %esi 4/r32/esp
2020-05-17 18:00:25 +00:00
$test-add-reg-to-mem:initialize-stmt:
# var stmt/esi: (addr statement)
68/push 0/imm32/next
2020-05-17 18:00:25 +00:00
68/push 0/imm32/next
68/push 0/imm32/outputs
68/push 0/imm32/outputs
56/push-esi/inouts
2020-05-17 18:00:25 +00:00
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/operation
68/push 0/imm32/operation
68/push 1/imm32/tag:stmt1
89/<- %esi 4/r32/esp
2020-05-17 18:00:25 +00:00
$test-add-reg-to-mem:initialize-stmt-operation:
2020-05-17 23:42:28 +00:00
# stmt->operation = "add-to"
2020-05-17 18:00:25 +00:00
8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation
(copy-array Heap "add-to" %eax)
# convert
c7 0/subop/copy *Curr-block-depth 0/imm32
(emit-subx-stmt _test-output-buffered-file %esi Primitives)
(flush _test-output-buffered-file)
#? # dump _test-output-stream {{{
#? (write 2 "^")
#? (write-stream 2 _test-output-stream)
#? (write 2 "$\n")
#? (rewind-stream _test-output-stream)
#? # }}}
# check output
2019-12-26 10:21:55 +00:00
(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
# =>
2019-12-26 08:28:16 +00:00
# 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)
2020-05-17 22:49:08 +00:00
$test-add-mem-to-reg:initialize-type:
# var type/ecx: (payload 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
2020-01-13 04:25:11 +00:00
89/<- %ecx 4/r32/esp
2020-05-17 22:49:08 +00:00
$test-add-mem-to-reg:initialize-var:
# var var1/ecx: (payload var)
68/push 0/imm32/register
68/push 0/imm32/register
68/push 0/imm32/no-stack-offset
68/push 1/imm32/block-depth
2020-01-13 04:25:11 +00:00
51/push-ecx
2020-05-17 22:49:08 +00:00
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
2020-05-17 22:49:08 +00:00
$test-add-mem-to-reg:initialize-var-name:
# var1->name = "foo"
8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4
(copy-array Heap "var1" %eax)
$test-add-mem-to-reg:initialize-var-register:
# var1->register = "eax"
8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4
(copy-array Heap "eax" %eax)
$test-add-mem-to-reg:initialize-var2:
# var var2/edx: (payload var)
68/push 0/imm32/register
68/push 0/imm32/register
68/push 8/imm32/stack-offset
68/push 1/imm32/block-depth
2020-05-17 22:49:08 +00:00
ff 6/subop/push *(ecx+0x10)
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/name
68/push 0/imm32/name
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %edx 4/r32/esp
2020-05-17 22:49:08 +00:00
$test-add-mem-to-reg:initialize-var2-name:
# var2->name = "var2"
8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4
(copy-array Heap "var2" %eax)
$test-add-mem-to-reg:initialize-inouts:
# var inouts/esi: (payload stmt-var) = [var2]
68/push 0/imm32/is-deref:false
68/push 0/imm32/next
2020-05-17 22:49:08 +00:00
68/push 0/imm32/next
52/push-edx/var2
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %esi 4/r32/esp
2020-05-17 22:49:08 +00:00
$test-add-mem-to-reg:initialize-outputs:
# var outputs/edi: (payload stmt-var) = [var1]
68/push 0/imm32/is-deref:false
68/push 0/imm32/next
2020-05-17 22:49:08 +00:00
68/push 0/imm32/next
51/push-ecx/var1
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %edi 4/r32/esp
2020-05-17 22:49:08 +00:00
$test-add-mem-to-reg:initialize-stmt:
# var stmt/esi: (addr statement)
68/push 0/imm32/next
68/push 0/imm32/next
57/push-edi/outputs
2020-05-17 22:49:08 +00:00
68/push 0x11/imm32/alloc-id:fake
56/push-esi/inouts
2020-05-17 22:49:08 +00:00
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/operation
68/push 0/imm32/operation
68/push 1/imm32/tag:stmt1
89/<- %esi 4/r32/esp
2020-05-17 22:49:08 +00:00
$test-add-mem-to-reg:initialize-stmt-operation:
# stmt->operation = "add"
8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation
(copy-array Heap "add" %eax)
# convert
c7 0/subop/copy *Curr-block-depth 0/imm32
(emit-subx-stmt _test-output-buffered-file %esi Primitives)
(flush _test-output-buffered-file)
#? # dump _test-output-stream {{{
#? (write 2 "^")
#? (write-stream 2 _test-output-stream)
#? (write 2 "$\n")
#? (rewind-stream _test-output-stream)
#? # }}}
# check output
2019-12-26 08:28:16 +00:00
(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
2019-12-26 08:28:16 +00:00
test-add-literal-to-eax:
# var1/eax <- add 0x34
# =>
2019-12-26 08:28:16 +00:00
# 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)
2020-05-17 22:54:47 +00:00
$test-add-literal-to-eax:initialize-var-type:
# var type/ecx: (payload 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
2020-01-13 04:25:11 +00:00
89/<- %ecx 4/r32/esp
2020-05-17 22:54:47 +00:00
$test-add-literal-to-eax:initialize-var:
# var v/ecx: (payload var)
68/push 0/imm32/register
68/push 0/imm32/register
68/push 0/imm32/no-stack-offset
68/push 1/imm32/block-depth
2020-01-13 04:25:11 +00:00
51/push-ecx
2020-05-17 22:54:47 +00:00
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
2020-05-17 22:54:47 +00:00
$test-add-literal-to-eax:initialize-var-name:
# v->name = "v"
8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4
(copy-array Heap "v" %eax)
$test-add-literal-to-eax:initialize-var-register:
# v->register = "eax"
8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4
(copy-array Heap "eax" %eax)
$test-add-literal-to-eax:initialize-literal-type:
# var type/edx: (payload tree type-id) = literal
68/push 0/imm32/right:null
68/push 0/imm32/right:null
68/push 0/imm32/left:unused
68/push 0/imm32/value:literal
68/push 1/imm32/is-atom?:true
68/push 0x11/imm32/alloc-id:fake:payload
2020-01-13 04:25:11 +00:00
89/<- %edx 4/r32/esp
2020-05-17 22:54:47 +00:00
$test-add-literal-to-eax:initialize-literal:
# var l/edx: (payload var)
68/push 0/imm32/register
68/push 0/imm32/register
68/push 0/imm32/no-stack-offset
68/push 1/imm32/block-depth
2020-01-13 04:25:11 +00:00
52/push-edx
2020-05-17 22:54:47 +00:00
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/name
68/push 0/imm32/name
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %edx 4/r32/esp
2020-05-17 22:54:47 +00:00
$test-add-literal-to-eax:initialize-literal-value:
# l->name = "0x34"
8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4
(copy-array Heap "0x34" %eax)
$test-add-literal-to-eax:initialize-inouts:
# var inouts/esi: (payload stmt-var) = [l]
68/push 0/imm32/is-deref:false
68/push 0/imm32/next
2020-05-17 22:54:47 +00:00
68/push 0/imm32/next
52/push-edx/l
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %esi 4/r32/esp
2020-05-17 22:54:47 +00:00
$test-add-literal-to-eax:initialize-outputs:
# var outputs/edi: (payload stmt-var) = [v]
68/push 0/imm32/is-deref:false
68/push 0/imm32/next
2020-05-17 22:54:47 +00:00
68/push 0/imm32/next
51/push-ecx/v
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %edi 4/r32/esp
2020-05-17 22:54:47 +00:00
$test-add-literal-to-eax:initialize-stmt:
# var stmt/esi: (addr statement)
68/push 0/imm32/next
68/push 0/imm32/next
57/push-edi/outputs
2020-05-17 22:54:47 +00:00
68/push 0x11/imm32/alloc-id:fake
56/push-esi/inouts
2020-05-17 22:54:47 +00:00
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/operation
68/push 0/imm32/operation
68/push 1/imm32/tag:stmt1
89/<- %esi 4/r32/esp
2020-05-17 22:54:47 +00:00
$test-add-literal-to-eax:initialize-stmt-operation:
# stmt->operation = "add"
8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation
(copy-array Heap "add" %eax)
# convert
c7 0/subop/copy *Curr-block-depth 0/imm32
(emit-subx-stmt _test-output-buffered-file %esi Primitives)
(flush _test-output-buffered-file)
#? # dump _test-output-stream {{{
#? (write 2 "^")
#? (write-stream 2 _test-output-stream)
#? (write 2 "$\n")
#? (rewind-stream _test-output-stream)
#? # }}}
# check output
2019-12-26 08:28:16 +00:00
(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)
2020-05-17 23:31:58 +00:00
$test-add-literal-to-reg:initialize-var-type:
# var type/ecx: (payload 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
2020-01-13 04:25:11 +00:00
89/<- %ecx 4/r32/esp
2020-05-17 23:31:58 +00:00
$test-add-literal-to-reg:initialize-var:
# var v/ecx: (payload var)
68/push 0/imm32/register
68/push 0/imm32/register
2019-12-26 08:28:16 +00:00
68/push 0/imm32/no-stack-offset
68/push 1/imm32/block-depth
2020-01-13 04:25:11 +00:00
51/push-ecx
2020-05-17 23:31:58 +00:00
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
2019-12-26 08:28:16 +00:00
89/<- %ecx 4/r32/esp
2020-05-17 23:31:58 +00:00
$test-add-literal-to-reg:initialize-var-name:
# v->name = "v"
8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4
(copy-array Heap "v" %eax)
$test-add-literal-to-reg:initialize-var-register:
# v->register = "ecx"
8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4
(copy-array Heap "ecx" %eax)
$test-add-literal-to-reg:initialize-literal-type:
# var type/edx: (payload tree type-id) = literal
68/push 0/imm32/right:null
68/push 0/imm32/right:null
68/push 0/imm32/left:unused
68/push 0/imm32/value:literal
68/push 1/imm32/is-atom?:true
68/push 0x11/imm32/alloc-id:fake:payload
2020-01-13 04:25:11 +00:00
89/<- %edx 4/r32/esp
2020-05-17 23:31:58 +00:00
$test-add-literal-to-reg:initialize-literal:
# var l/edx: (payload var)
68/push 0/imm32/register
68/push 0/imm32/register
2019-12-26 08:28:16 +00:00
68/push 0/imm32/no-stack-offset
68/push 1/imm32/block-depth
2020-01-13 04:25:11 +00:00
52/push-edx
2020-05-17 23:31:58 +00:00
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
2019-12-26 08:28:16 +00:00
89/<- %edx 4/r32/esp
2020-05-17 23:31:58 +00:00
$test-add-literal-to-reg:initialize-literal-value:
# l->name = "0x34"
8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4
(copy-array Heap "0x34" %eax)
$test-add-literal-to-reg:initialize-inouts:
# var inouts/esi: (payload stmt-var) = [l]
68/push 0/imm32/is-deref:false
2019-12-26 08:28:16 +00:00
68/push 0/imm32/next
2020-05-17 23:31:58 +00:00
68/push 0/imm32/next
52/push-edx/l
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
2019-12-26 08:28:16 +00:00
89/<- %esi 4/r32/esp
2020-05-17 23:31:58 +00:00
$test-add-literal-to-reg:initialize-outputs:
# var outputs/edi: (payload stmt-var) = [v]
68/push 0/imm32/is-deref:false
2019-12-26 08:28:16 +00:00
68/push 0/imm32/next
2020-05-17 23:31:58 +00:00
68/push 0/imm32/next
51/push-ecx/v
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
2019-12-26 08:28:16 +00:00
89/<- %edi 4/r32/esp
2020-05-17 23:31:58 +00:00
$test-add-literal-to-reg:initialize-stmt:
# var stmt/esi: (addr statement)
68/push 0/imm32/next
2019-12-26 08:28:16 +00:00
68/push 0/imm32/next
57/push-edi/outputs
2020-05-17 23:31:58 +00:00
68/push 0x11/imm32/alloc-id:fake
2019-12-26 08:28:16 +00:00
56/push-esi/inouts
2020-05-17 23:31:58 +00:00
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/operation
68/push 0/imm32/operation
68/push 1/imm32/tag:stmt1
2019-12-26 08:28:16 +00:00
89/<- %esi 4/r32/esp
2020-05-17 23:31:58 +00:00
$test-add-literal-to-reg:initialize-stmt-operation:
# stmt->operation = "add"
8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation
(copy-array Heap "add" %eax)
2019-12-26 08:28:16 +00:00
# convert
c7 0/subop/copy *Curr-block-depth 0/imm32
(emit-subx-stmt _test-output-buffered-file %esi Primitives)
2019-12-26 08:28:16 +00:00
(flush _test-output-buffered-file)
#? # dump _test-output-stream {{{
#? (write 2 "^")
#? (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
2019-11-27 02:07:55 +00:00
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)
2020-05-17 23:37:12 +00:00
$test-add-literal-to-mem:initialize-type:
# var type/ecx: (payload 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
2020-01-13 04:25:11 +00:00
89/<- %ecx 4/r32/esp
2020-05-17 23:37:12 +00:00
$test-add-literal-to-mem:initialize-var1:
# var var1/ecx: (payload var)
68/push 0/imm32/register
68/push 0/imm32/register
2019-11-27 02:07:55 +00:00
68/push 8/imm32/stack-offset
68/push 1/imm32/block-depth
2020-01-13 04:25:11 +00:00
51/push-ecx
2020-05-17 23:37:12 +00:00
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
2019-11-27 02:07:55 +00:00
89/<- %ecx 4/r32/esp
2020-05-17 23:37:12 +00:00
$test-add-literal-to-mem:initialize-var1-name:
# var1->name = "var1"
8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4
(copy-array Heap "var1" %eax)
$test-add-literal-to-mem:initialize-literal-type:
# var type/edx: (payload tree type-id) = literal
68/push 0/imm32/right:null
68/push 0/imm32/right:null
68/push 0/imm32/left:unused
68/push 0/imm32/value:literal
68/push 1/imm32/is-atom?:true
68/push 0x11/imm32/alloc-id:fake:payload
2020-01-13 04:25:11 +00:00
89/<- %edx 4/r32/esp
2020-05-17 23:37:12 +00:00
$test-add-literal-to-mem:initialize-literal:
# var l/edx: (payload var)
68/push 0/imm32/register
68/push 0/imm32/register
2019-11-27 02:07:55 +00:00
68/push 0/imm32/no-stack-offset
68/push 1/imm32/block-depth
2020-01-13 04:25:11 +00:00
52/push-edx
2020-05-17 23:37:12 +00:00
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
2019-11-27 02:07:55 +00:00
89/<- %edx 4/r32/esp
2020-05-17 23:37:12 +00:00
$test-add-literal-to-mem:initialize-literal-value:
# l->name = "0x34"
8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4
(copy-array Heap "0x34" %eax)
$test-add-literal-to-mem:initialize-inouts:
# var inouts/esi: (payload stmt-var) = [l]
68/push 0/imm32/is-deref:false
2019-11-27 02:07:55 +00:00
68/push 0/imm32/next
2020-05-17 23:37:12 +00:00
68/push 0/imm32/next
52/push-edx/l
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
2019-11-27 02:07:55 +00:00
89/<- %esi 4/r32/esp
# var inouts = (handle stmt-var) = [var1, var2]
68/push 0/imm32/is-deref:false
2019-11-27 02:07:55 +00:00
56/push-esi/next
2020-05-17 23:37:12 +00:00
68/push 0x11/imm32/alloc-id:fake
51/push-ecx/var1
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
2019-11-27 02:07:55 +00:00
89/<- %esi 4/r32/esp
2020-05-17 23:37:12 +00:00
$test-add-literal-to-mem:initialize-stmt:
# var stmt/esi: (addr statement)
2019-11-27 02:07:55 +00:00
68/push 0/imm32/next
2020-05-17 23:37:12 +00:00
68/push 0/imm32/next
68/push 0/imm32/outputs
68/push 0/imm32/outputs
2019-11-27 02:07:55 +00:00
56/push-esi/inouts
2020-05-17 23:37:12 +00:00
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/operation
68/push 0/imm32/operation
68/push 1/imm32/tag:stmt1
2019-11-27 02:07:55 +00:00
89/<- %esi 4/r32/esp
2020-05-17 23:37:12 +00:00
$test-add-literal-to-mem:initialize-stmt-operation:
# stmt->operation = "add-to"
8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation
(copy-array Heap "add-to" %eax)
2019-11-27 02:07:55 +00:00
# convert
c7 0/subop/copy *Curr-block-depth 0/imm32
(emit-subx-stmt _test-output-buffered-file %esi Primitives)
2019-11-27 02:07:55 +00:00
(flush _test-output-buffered-file)
#? # dump _test-output-stream {{{
#? (write 2 "^")
#? (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
2020-01-30 03:43:20 +00:00
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)
2020-05-17 23:42:28 +00:00
$test-compare-mem-with-reg:initialize-type:
# var type/ecx: (payload 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
2020-01-30 03:43:20 +00:00
89/<- %ecx 4/r32/esp
2020-05-17 23:42:28 +00:00
$test-compare-mem-with-reg:initialize-var1:
# var var1/ecx: (payload var)
68/push 0/imm32/register
68/push 0/imm32/register
68/push 8/imm32/stack-offset
2020-01-30 03:43:20 +00:00
68/push 1/imm32/block-depth
51/push-ecx
2020-05-17 23:42:28 +00:00
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
2020-01-30 03:43:20 +00:00
89/<- %ecx 4/r32/esp
2020-05-17 23:42:28 +00:00
$test-compare-mem-with-reg:initialize-var1-name:
# var1->name = "var1"
8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4
(copy-array Heap "var1" %eax)
$test-compare-mem-with-reg:initialize-var2:
# var var2/edx: (payload var)
68/push 0/imm32/register
68/push 0/imm32/register
68/push 0/imm32/no-stack-offset
2020-01-30 03:43:20 +00:00
68/push 1/imm32/block-depth
2020-05-17 23:42:28 +00:00
ff 6/subop/push *(ecx+0x10)
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/name
68/push 0/imm32/name
68/push 0x11/imm32/alloc-id:fake:payload
2020-01-30 03:43:20 +00:00
89/<- %edx 4/r32/esp
2020-05-17 23:42:28 +00:00
$test-compare-mem-with-reg:initialize-var2-name:
# var2->name = "var2"
8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4
(copy-array Heap "var2" %eax)
$test-compare-mem-with-reg:initialize-var2-register:
# var2->register = "eax"
8d/copy-address *(edx+0x1c) 0/r32/eax # Var-register + 4
(copy-array Heap "eax" %eax)
$test-compare-mem-with-reg:initialize-inouts:
# var inouts/esi: (payload stmt-var) = [var2]
68/push 0/imm32/is-deref:false
2020-01-30 03:43:20 +00:00
68/push 0/imm32/next
2020-05-17 23:42:28 +00:00
68/push 0/imm32/next
52/push-edx/var2
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
2020-01-30 03:43:20 +00:00
89/<- %esi 4/r32/esp
# inouts = [var1, var2]
68/push 0/imm32/is-deref:false
2020-05-17 23:42:28 +00:00
56/push-esi/next
68/push 0x11/imm32/alloc-id:fake
51/push-ecx/var1
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
2020-01-30 03:43:20 +00:00
89/<- %esi 4/r32/esp
2020-05-17 23:42:28 +00:00
$test-compare-mem-with-reg:initialize-stmt:
# var stmt/esi: (addr statement)
2020-01-30 03:43:20 +00:00
68/push 0/imm32/next
2020-05-17 23:42:28 +00:00
68/push 0/imm32/next
68/push 0/imm32/outputs
68/push 0/imm32/outputs
2020-01-30 03:43:20 +00:00
56/push-esi/inouts
2020-05-17 23:42:28 +00:00
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/operation
68/push 0/imm32/operation
68/push 1/imm32/tag:stmt1
2020-01-30 03:43:20 +00:00
89/<- %esi 4/r32/esp
2020-05-17 23:42:28 +00:00
$test-compare-mem-with-reg:initialize-stmt-operation:
# stmt->operation = "compare"
8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation
(copy-array Heap "compare" %eax)
2020-01-30 03:43:20 +00:00
# convert
c7 0/subop/copy *Curr-block-depth 0/imm32
(emit-subx-stmt _test-output-buffered-file %esi Primitives)
2020-01-30 03:43:20 +00:00
(flush _test-output-buffered-file)
#? # dump _test-output-stream {{{
#? (write 2 "^")
#? (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")
2020-01-30 03:43:20 +00:00
# . 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
2020-01-30 03:43:20 +00:00
#
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(clear-stream _test-output-stream)
(clear-stream $_test-output-buffered-file->buffer)
2020-05-17 23:44:28 +00:00
$test-compare-reg-with-mem:initialize-type:
# var type/ecx: (payload 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
2020-01-30 03:43:20 +00:00
89/<- %ecx 4/r32/esp
2020-05-17 23:44:28 +00:00
$test-compare-reg-with-mem:initialize-var1:
# var var1/ecx: (payload var)
68/push 0/imm32/register
68/push 0/imm32/register
2020-01-30 03:43:20 +00:00
68/push 0/imm32/no-stack-offset
68/push 1/imm32/block-depth
51/push-ecx
2020-05-17 23:44:28 +00:00
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
2020-01-30 03:43:20 +00:00
89/<- %ecx 4/r32/esp
2020-05-17 23:44:28 +00:00
$test-compare-reg-with-mem:initialize-var1-name:
# var1->name = "var1"
8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4
(copy-array Heap "var1" %eax)
$test-compare-reg-with-mem:initialize-var1-register:
# var1->register = "eax"
8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4
(copy-array Heap "eax" %eax)
$test-compare-reg-with-mem:initialize-var2:
# var var2/edx: (payload var)
68/push 0/imm32/register
68/push 0/imm32/register
2020-01-30 03:43:20 +00:00
68/push 8/imm32/stack-offset
68/push 1/imm32/block-depth
2020-05-17 23:44:28 +00:00
ff 6/subop/push *(ecx+0x10)
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/name
68/push 0/imm32/name
68/push 0x11/imm32/alloc-id:fake:payload
2020-01-30 03:43:20 +00:00
89/<- %edx 4/r32/esp
2020-05-17 23:44:28 +00:00
$test-compare-reg-with-mem:initialize-var2-name:
# var2->name = "var2"
8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4
(copy-array Heap "var2" %eax)
$test-compare-reg-with-mem:initialize-inouts:
# var inouts/esi: (payload stmt-var) = [var2]
68/push 0/imm32/is-deref:false
2020-01-30 03:43:20 +00:00
68/push 0/imm32/next
2020-05-17 23:44:28 +00:00
68/push 0/imm32/next
52/push-edx/var2
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
2020-01-30 03:43:20 +00:00
89/<- %esi 4/r32/esp
# inouts = [var1, var2]
68/push 0/imm32/is-deref:false
2020-05-17 23:44:28 +00:00
56/push-esi/next
68/push 0x11/imm32/alloc-id:fake
51/push-ecx/var1
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
2020-01-30 03:43:20 +00:00
89/<- %esi 4/r32/esp
2020-05-17 23:44:28 +00:00
$test-compare-reg-with-mem:initialize-stmt:
# var stmt/esi: (addr statement)
2020-01-30 03:43:20 +00:00
68/push 0/imm32/next
2020-05-17 23:44:28 +00:00
68/push 0/imm32/next
68/push 0/imm32/outputs
68/push 0/imm32/outputs
2020-01-30 03:43:20 +00:00
56/push-esi/inouts
2020-05-17 23:44:28 +00:00
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/operation
68/push 0/imm32/operation
68/push 1/imm32/tag:stmt1
2020-01-30 03:43:20 +00:00
89/<- %esi 4/r32/esp
2020-05-17 23:44:28 +00:00
$test-compare-reg-with-mem:initialize-stmt-operation:
# stmt->operation = "compare"
8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation
(copy-array Heap "compare" %eax)
2020-01-30 03:43:20 +00:00
# convert
c7 0/subop/copy *Curr-block-depth 0/imm32
(emit-subx-stmt _test-output-buffered-file %esi Primitives)
2020-01-30 03:43:20 +00:00
(flush _test-output-buffered-file)
#? # dump _test-output-stream {{{
#? (write 2 "^")
#? (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")
2020-01-30 03:43:20 +00:00
# . 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)
2020-05-17 23:48:51 +00:00
$test-compare-mem-with-literal:initialize-type:
# var type/ecx: (payload 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
2020-01-30 03:43:20 +00:00
89/<- %ecx 4/r32/esp
2020-05-17 23:48:51 +00:00
$test-compare-mem-with-literal:initialize-var1:
# var var1/ecx: (payload var)
68/push 0/imm32/register
68/push 0/imm32/register
2020-01-30 03:43:20 +00:00
68/push 8/imm32/stack-offset
68/push 1/imm32/block-depth
51/push-ecx
2020-05-17 23:48:51 +00:00
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
2020-01-30 03:43:20 +00:00
89/<- %ecx 4/r32/esp
2020-05-17 23:48:51 +00:00
$test-compare-mem-with-literal:initialize-var1-name:
# var1->name = "var1"
8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4
(copy-array Heap "var1" %eax)
$test-compare-mem-with-literal:initialize-literal-type:
# var type/edx: (payload tree type-id) = literal
68/push 0/imm32/right:null
68/push 0/imm32/right:null
68/push 0/imm32/left:unused
68/push 0/imm32/value:literal
68/push 1/imm32/is-atom?:true
68/push 0x11/imm32/alloc-id:fake:payload
2020-01-30 03:43:20 +00:00
89/<- %edx 4/r32/esp
2020-05-17 23:48:51 +00:00
$test-compare-mem-with-literal:initialize-literal:
# var l/edx: (payload var)
68/push 0/imm32/register
68/push 0/imm32/register
2020-01-30 03:43:20 +00:00
68/push 0/imm32/no-stack-offset
68/push 1/imm32/block-depth
52/push-edx
2020-05-17 23:48:51 +00:00
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
2020-01-30 03:43:20 +00:00
89/<- %edx 4/r32/esp
2020-05-17 23:48:51 +00:00
$test-compare-mem-with-literal:initialize-literal-value:
# l->name = "0x34"
8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4
(copy-array Heap "0x34" %eax)
$test-compare-mem-with-literal:initialize-inouts:
# var inouts/esi: (payload stmt-var) = [l]
68/push 0/imm32/is-deref:false
2020-01-30 03:43:20 +00:00
68/push 0/imm32/next
2020-05-17 23:48:51 +00:00
68/push 0/imm32/next
52/push-edx/l
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
2020-01-30 03:43:20 +00:00
89/<- %esi 4/r32/esp
2020-05-17 23:48:51 +00:00
# var inouts = (handle stmt-var) = [var1, var2]
68/push 0/imm32/is-deref:false
2020-01-30 03:43:20 +00:00
56/push-esi/next
2020-05-17 23:48:51 +00:00
68/push 0x11/imm32/alloc-id:fake
51/push-ecx/var1
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
2020-01-30 03:43:20 +00:00
89/<- %esi 4/r32/esp
2020-05-17 23:48:51 +00:00
$test-compare-mem-with-literal:initialize-stmt:
# var stmt/esi: (addr statement)
2020-01-30 03:43:20 +00:00
68/push 0/imm32/next
2020-05-17 23:48:51 +00:00
68/push 0/imm32/next
68/push 0/imm32/outputs
68/push 0/imm32/outputs
2020-01-30 03:43:20 +00:00
56/push-esi/inouts
2020-05-17 23:48:51 +00:00
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/operation
68/push 0/imm32/operation
68/push 1/imm32/tag:stmt1
2020-01-30 03:43:20 +00:00
89/<- %esi 4/r32/esp
2020-05-17 23:48:51 +00:00
$test-compare-mem-with-literal:initialize-stmt-operation:
# stmt->operation = "compare"
8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation
(copy-array Heap "compare" %eax)
2020-01-30 03:43:20 +00:00
# convert
c7 0/subop/copy *Curr-block-depth 0/imm32
(emit-subx-stmt _test-output-buffered-file %esi Primitives)
2020-01-30 03:43:20 +00:00
(flush _test-output-buffered-file)
#? # dump _test-output-stream {{{
#? (write 2 "^")
#? (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)
2020-05-17 23:59:04 +00:00
$test-compare-eax-with-literal:initialize-type:
# var type/ecx: (payload 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
2020-01-30 03:43:20 +00:00
89/<- %ecx 4/r32/esp
2020-05-17 23:59:04 +00:00
$test-compare-eax-with-literal:initialize-var1:
# var var1/ecx: (payload var)
68/push 0/imm32/register
68/push 0/imm32/register
2020-01-30 03:43:20 +00:00
68/push 0/imm32/no-stack-offset
68/push 1/imm32/block-depth
51/push-ecx
2020-05-17 23:59:04 +00:00
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
2020-01-30 03:43:20 +00:00
89/<- %ecx 4/r32/esp
2020-05-17 23:59:04 +00:00
$test-compare-eax-with-literal:initialize-var1-name:
# var1->name = "var1"
8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4
(copy-array Heap "var1" %eax)
$test-compare-eax-with-literal:initialize-var1-register:
# v->register = "eax"
8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4
(copy-array Heap "eax" %eax)
$test-compare-eax-with-literal:initialize-literal-type:
# var type/edx: (payload tree type-id) = literal
68/push 0/imm32/right:null
68/push 0/imm32/right:null
68/push 0/imm32/left:unused
68/push 0/imm32/value:literal
68/push 1/imm32/is-atom?:true
68/push 0x11/imm32/alloc-id:fake:payload
2020-01-30 03:43:20 +00:00
89/<- %edx 4/r32/esp
2020-05-17 23:59:04 +00:00
$test-compare-eax-with-literal:initialize-literal:
# var l/edx: (payload var)
68/push 0/imm32/register
68/push 0/imm32/register
2020-01-30 03:43:20 +00:00
68/push 0/imm32/no-stack-offset
68/push 1/imm32/block-depth
52/push-edx
2020-05-17 23:59:04 +00:00
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
2020-01-30 03:43:20 +00:00
89/<- %edx 4/r32/esp
2020-05-17 23:59:04 +00:00
$test-compare-eax-with-literal:initialize-literal-value:
# l->name = "0x34"
8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4
(copy-array Heap "0x34" %eax)
$test-compare-eax-with-literal:initialize-inouts:
# var inouts/esi: (payload stmt-var) = [l]
68/push 0/imm32/is-deref:false
2020-01-30 03:43:20 +00:00
68/push 0/imm32/next
2020-05-17 23:59:04 +00:00
68/push 0/imm32/next
52/push-edx/l
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
2020-01-30 03:43:20 +00:00
89/<- %esi 4/r32/esp
2020-05-17 23:59:04 +00:00
# var inouts = (handle stmt-var) = [var1, var2]
68/push 0/imm32/is-deref:false
2020-01-30 03:43:20 +00:00
56/push-esi/next
2020-05-17 23:59:04 +00:00
68/push 0x11/imm32/alloc-id:fake
51/push-ecx/var1
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
2020-01-30 03:43:20 +00:00
89/<- %esi 4/r32/esp
2020-05-17 23:59:04 +00:00
$test-compare-eax-with-literal:initialize-stmt:
# var stmt/esi: (addr statement)
2020-01-30 03:43:20 +00:00
68/push 0/imm32/next
2020-05-17 23:59:04 +00:00
68/push 0/imm32/next
68/push 0/imm32/outputs
68/push 0/imm32/outputs
2020-01-30 03:43:20 +00:00
56/push-esi/inouts
2020-05-17 23:59:04 +00:00
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/operation
68/push 0/imm32/operation
68/push 1/imm32/tag:stmt1
2020-01-30 03:43:20 +00:00
89/<- %esi 4/r32/esp
2020-05-17 23:59:04 +00:00
$test-compare-eax-with-literal:initialize-stmt-operation:
# stmt->operation = "compare"
8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation
(copy-array Heap "compare" %eax)
2020-01-30 03:43:20 +00:00
# convert
c7 0/subop/copy *Curr-block-depth 0/imm32
(emit-subx-stmt _test-output-buffered-file %esi Primitives)
2020-01-30 03:43:20 +00:00
(flush _test-output-buffered-file)
#? # dump _test-output-stream {{{
#? (write 2 "^")
#? (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)
2020-05-18 00:00:04 +00:00
$test-compare-reg-with-literal:initialize-type:
# var type/ecx: (payload 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
2020-01-30 03:43:20 +00:00
89/<- %ecx 4/r32/esp
2020-05-18 00:00:04 +00:00
$test-compare-reg-with-literal:initialize-var1:
# var var1/ecx: (payload var)
68/push 0/imm32/register
68/push 0/imm32/register
2020-01-30 03:43:20 +00:00
68/push 0/imm32/no-stack-offset
68/push 1/imm32/block-depth
51/push-ecx
2020-05-18 00:00:04 +00:00
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
2020-01-30 03:43:20 +00:00
89/<- %ecx 4/r32/esp
2020-05-18 00:00:04 +00:00
$test-compare-reg-with-literal:initialize-var1-name:
# var1->name = "var1"
8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4
(copy-array Heap "var1" %eax)
$test-compare-reg-with-literal:initialize-var1-register:
# v->register = "ecx"
8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4
(copy-array Heap "ecx" %eax)
$test-compare-reg-with-literal:initialize-literal-type:
# var type/edx: (payload tree type-id) = literal
68/push 0/imm32/right:null
68/push 0/imm32/right:null
68/push 0/imm32/left:unused
68/push 0/imm32/value:literal
68/push 1/imm32/is-atom?:true
68/push 0x11/imm32/alloc-id:fake:payload
2020-01-30 03:43:20 +00:00
89/<- %edx 4/r32/esp
2020-05-18 00:00:04 +00:00
$test-compare-reg-with-literal:initialize-literal:
# var l/edx: (payload var)
68/push 0/imm32/register
68/push 0/imm32/register
2020-01-30 03:43:20 +00:00
68/push 0/imm32/no-stack-offset
68/push 1/imm32/block-depth
52/push-edx
2020-05-18 00:00:04 +00:00
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
2020-01-30 03:43:20 +00:00
89/<- %edx 4/r32/esp
2020-05-18 00:00:04 +00:00
$test-compare-reg-with-literal:initialize-literal-value:
# l->name = "0x34"
8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4
(copy-array Heap "0x34" %eax)
$test-compare-reg-with-literal:initialize-inouts:
# var inouts/esi: (payload stmt-var) = [l]
68/push 0/imm32/is-deref:false
2020-01-30 03:43:20 +00:00
68/push 0/imm32/next
2020-05-18 00:00:04 +00:00
68/push 0/imm32/next
52/push-edx/l
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
2020-01-30 03:43:20 +00:00
89/<- %esi 4/r32/esp
2020-05-18 00:00:04 +00:00
# var inouts = (handle stmt-var) = [var1, var2]
68/push 0/imm32/is-deref:false
2020-01-30 03:43:20 +00:00
56/push-esi/next
2020-05-18 00:00:04 +00:00
68/push 0x11/imm32/alloc-id:fake
51/push-ecx/var1
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
2020-01-30 03:43:20 +00:00
89/<- %esi 4/r32/esp
2020-05-18 00:00:04 +00:00
$test-compare-reg-with-literal:initialize-stmt:
# var stmt/esi: (addr statement)
2020-01-30 03:43:20 +00:00
68/push 0/imm32/next
2020-05-18 00:00:04 +00:00
68/push 0/imm32/next
68/push 0/imm32/outputs
68/push 0/imm32/outputs
2020-01-30 03:43:20 +00:00
56/push-esi/inouts
2020-05-18 00:00:04 +00:00
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/operation
68/push 0/imm32/operation
68/push 1/imm32/tag:stmt1
2020-01-30 03:43:20 +00:00
89/<- %esi 4/r32/esp
2020-05-18 00:00:04 +00:00
$test-compare-reg-with-literal:initialize-stmt-operation:
# stmt->operation = "compare"
8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation
(copy-array Heap "compare" %eax)
2020-01-30 03:43:20 +00:00
# convert
c7 0/subop/copy *Curr-block-depth 0/imm32
(emit-subx-stmt _test-output-buffered-file %esi Primitives)
2020-01-30 03:43:20 +00:00
(flush _test-output-buffered-file)
#? # dump _test-output-stream {{{
#? (write 2 "^")
#? (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
2020-02-21 23:36:18 +00:00
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
2019-11-15 01:39:32 +00:00
# stack-offset: -8
#
# There's nothing in primitives.
#
# We don't perform any checking here on the type of 'f'.
#
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(clear-stream _test-output-stream)
(clear-stream $_test-output-buffered-file->buffer)
$test-emit-subx-function-call:initialize-type:
# var type/ecx: (payload 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
2020-01-13 04:25:11 +00:00
89/<- %ecx 4/r32/esp
$test-emit-subx-function-call:initialize-var:
# var var-foo/ecx: (payload var) = var(type)
68/push 0/imm32/no-register
68/push 0/imm32/no-register
68/push -8/imm32/stack-offset
68/push 1/imm32/block-depth
51/push-ecx/type
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/name
68/push 0/imm32/name
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %ecx 4/r32/esp
$test-emit-subx-function-call:initialize-var-name:
# var-foo->name = "foo"
8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4
(copy-array Heap "foo" %eax)
$test-emit-subx-function-call:initialize-stmt-var:
# var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
68/push 0/imm32/is-deref:false
68/push 0/imm32/next
68/push 0/imm32/next
51/push-ecx/var-foo
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %ebx 4/r32/esp
$test-emit-subx-function-call:initialize-stmt:
# var stmt/esi: (addr statement)
2020-05-17 01:37:45 +00:00
68/push 0/imm32/no-outputs
68/push 0/imm32/no-outputs
53/push-ebx/inouts
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/operation
68/push 0/imm32/operation
68/push 1/imm32/tag
89/<- %esi 4/r32/esp
$test-emit-subx-function-call:initialize-stmt-operation:
# stmt->operation = "f"
8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation
(copy-array Heap "f" %eax)
# convert
c7 0/subop/copy *Curr-block-depth 0/imm32
(emit-subx-stmt _test-output-buffered-file %esi 0)
(flush _test-output-buffered-file)
#? # dump _test-output-stream {{{
#? (write 2 "^")
#? (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
2020-02-21 23:36:18 +00:00
test-emit-subx-stmt-function-call-with-literal-arg:
# Call a function on a literal.
# f 0x34
# =>
# (f2 0x34)
#
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(clear-stream _test-output-stream)
(clear-stream $_test-output-buffered-file->buffer)
$test-emit-subx-function-call-with-literal-arg:initialize-type:
# var type/ecx: (payload tree type-id) = int
68/push 0/imm32/right:null
68/push 0/imm32/right:null
68/push 0/imm32/left:unused
68/push 0/imm32/value:literal
68/push 1/imm32/is-atom?:true
68/push 0x11/imm32/alloc-id:fake:payload
2020-01-13 04:25:11 +00:00
89/<- %ecx 4/r32/esp
$test-emit-subx-function-call-with-literal-arg:initialize-var:
# var var-foo/ecx: (payload var) = var(lit)
68/push 0/imm32/no-register
68/push 0/imm32/no-register
68/push 0/imm32/no-stack-offset
68/push 1/imm32/block-depth
51/push-ecx/type
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/name
68/push 0/imm32/name
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %ecx 4/r32/esp
$test-emit-subx-function-call-with-literal-arg:initialize-var-name:
# var-foo->name = "0x34"
8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4
(copy-array Heap "0x34" %eax)
$test-emit-subx-function-call-with-literal-arg:initialize-stmt-var:
# var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
68/push 0/imm32/is-deref:false
68/push 0/imm32/next
68/push 0/imm32/next
51/push-ecx/var-foo
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %ebx 4/r32/esp
$test-emit-subx-function-call-with-literal-arg:initialize-stmt:
# var stmt/esi: (addr statement)
2020-05-17 01:37:45 +00:00
68/push 0/imm32/no-outputs
68/push 0/imm32/no-outputs
53/push-ebx/inouts
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/operation
68/push 0/imm32/operation
68/push 1/imm32/tag
89/<- %esi 4/r32/esp
$test-emit-subx-function-call-with-literal-arg:initialize-stmt-operation:
# stmt->operation = "f"
8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation
(copy-array Heap "f" %eax)
# convert
c7 0/subop/copy *Curr-block-depth 0/imm32
2020-02-21 23:36:18 +00:00
(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 0x34)" "F - test-emit-subx-stmt-function-call-with-literal-arg")
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
emit-indent: # out: (addr buffered-file), n: int
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
# var i/eax: int = n
8b/-> *(ebp+0xc) 0/r32/eax
{
# if (i <= 0) break
3d/compare-eax-with 0/imm32
7e/jump-if-<= break/disp8
(write-buffered *(ebp+8) " ")
48/decrement-eax
eb/jump loop/disp8
}
$emit-indent:end:
# . restore registers
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
2020-01-27 08:36:44 +00:00
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")
2019-11-09 01:31:11 +00:00
$emit-subx-prologue:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
2020-01-27 08:36:44 +00:00
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")
2019-11-09 01:31:11 +00:00
$emit-subx-epilogue:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return