aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/wasm_compile_arithm/words_to_verify.mem8
l---------tests/wasm_compile_block/Makefile1
-rw-r--r--tests/wasm_compile_block/instructions.wat121
l---------tests/wasm_compile_block/test.v1
-rw-r--r--tests/wasm_compile_block/words_to_verify.mem7
-rw-r--r--tests/wasm_compile_br_if/words_to_verify.mem6
-rw-r--r--tests/wasm_compile_function_call/words_to_verify.mem3
-rw-r--r--tests/wasm_compile_if_else/words_to_verify.mem4
-rw-r--r--tests/wasm_compile_loop/words_to_verify.mem2
-rw-r--r--tests/wasm_compile_simple_module/test.v6
-rw-r--r--tests/wasm_compile_simple_module/words_to_verify.mem2
-rw-r--r--tools/assemble.c38
-rw-r--r--tools/parse_module.c2
-rw-r--r--tools/stack_machine_instruction.h7
-rw-r--r--tools/translate.c35
-rw-r--r--tools/translate_xmacro.h1
-rw-r--r--tools/wasm.h1
-rw-r--r--tools/wasm_compile.c26
-rw-r--r--tools/wasm_compile.h12
19 files changed, 225 insertions, 58 deletions
diff --git a/tests/wasm_compile_arithm/words_to_verify.mem b/tests/wasm_compile_arithm/words_to_verify.mem
index d3f3c4e..078cd6d 100644
--- a/tests/wasm_compile_arithm/words_to_verify.mem
+++ b/tests/wasm_compile_arithm/words_to_verify.mem
@@ -1,7 +1,7 @@
// address value
0FFFFC 23
- 200 FFEFE021
- 204 16D3B7
- 208 ED8
- 20C 3C773E7C
+ 400 FFEFE021
+ 404 16D3B7
+ 408 ED8
+ 40C 3C773E7C
diff --git a/tests/wasm_compile_block/Makefile b/tests/wasm_compile_block/Makefile
new file mode 120000
index 0000000..e451c8b
--- /dev/null
+++ b/tests/wasm_compile_block/Makefile
@@ -0,0 +1 @@
+../wasm_compile_simple_module/Makefile \ No newline at end of file
diff --git a/tests/wasm_compile_block/instructions.wat b/tests/wasm_compile_block/instructions.wat
new file mode 100644
index 0000000..11b179d
--- /dev/null
+++ b/tests/wasm_compile_block/instructions.wat
@@ -0,0 +1,121 @@
+;; The idea is - we have 4 blocks, one inside another. We enter subsequent
+;; blocks (how many we enter, depends on $blockfun's first arg) and then we
+;; start leaving them. We "normally" (e.g. without br) exit some blocks (number
+;; depending on $blockfun's 2nd arg) and then we break out of the outermost one
+;; with the use of br_if.
+;; When making this "path" through blocks, we also construct a result value.
+;; The result value is initially 0 and upon each "normal" exit from a block,
+;; one bit is being set to 1 in the result. Which bit is set, depends on the
+;; block being left. Block 1 sets bit 0, block 2 sets bit 1, etc.
+;; So, the entire function actually computes an integer with bits a1-a2 through
+;; a1 set, with a1 and a2 being arguments to the function.
+;; To keep things simple, we limit this to 4 block and 4 bits, that can be set
+
+(module
+ (memory 0 1)
+ (func $blockfun
+ (param $blocks_to_enter i32)
+ (param $ones_to_set i32)
+ (result i32)
+
+ i32.const 0 ;; initial result value
+
+ get_local $blocks_to_enter
+ i32.const 0
+ i32.eq
+ br_if 0 ;; if number of blocks to enter is 0 - just return
+
+ block $b1 (param i32) (result i32)
+ get_local $blocks_to_enter
+ i32.const 1
+ i32.sub
+ set_local $blocks_to_enter
+
+ get_local $blocks_to_enter
+ if (param i32) (result i32)
+ block $b2 (param i32) (result i32)
+ get_local $blocks_to_enter
+ i32.const 1
+ i32.sub
+ set_local $blocks_to_enter
+
+ get_local $blocks_to_enter
+ if (param i32) (result i32)
+ block $b3 (param i32) (result i32)
+ get_local $blocks_to_enter
+ i32.const 1
+ i32.sub
+ set_local $blocks_to_enter
+
+ get_local $blocks_to_enter
+ if (param i32) (result i32)
+ block $b4 (param i32) (result i32)
+ get_local $ones_to_set
+ i32.const 0
+ i32.eq
+ br_if $b1
+
+ get_local $ones_to_set
+ i32.const 1
+ i32.sub
+ set_local $ones_to_set
+
+ i32.const 8 ;; block $b4 adds (1 << 3) to the result
+ i32.add
+ end
+ end
+
+ get_local $ones_to_set
+ i32.const 0
+ i32.eq
+ br_if $b1
+
+ get_local $ones_to_set
+ i32.const 1
+ i32.sub
+ set_local $ones_to_set
+
+ i32.const 4 ;; block $b3 adds (1 << 2) to the result
+ i32.add
+ end
+ end
+
+ get_local $ones_to_set
+ i32.const 0
+ i32.eq
+ br_if $b1
+
+ get_local $ones_to_set
+ i32.const 1
+ i32.sub
+ set_local $ones_to_set
+
+ i32.const 2 ;; block $b2 adds (1 << 1) to the result
+ i32.add
+ end
+ end
+
+ get_local $ones_to_set
+ i32.const 0
+ i32.eq
+ br_if $b1
+
+ get_local $ones_to_set
+ i32.const 1
+ i32.sub
+ set_local $ones_to_set
+
+ i32.const 1 ;; block $b1 adds (1 << 0) to the result
+ i32.add
+ end)
+ (func $main
+ (i32.store offset=0x0 align=2 (i32.const 0x0)
+ (call $blockfun (i32.const 4) (i32.const 2)))
+ (i32.store offset=0x0 align=2 (i32.const 0x4)
+ (call $blockfun (i32.const 3) (i32.const 2)))
+ (i32.store offset=0x0 align=2 (i32.const 0x8)
+ (call $blockfun (i32.const 2) (i32.const 0)))
+ (i32.store offset=0x0 align=2 (i32.const 0xC)
+ (call $blockfun (i32.const 4) (i32.const 4)))
+ )
+ (export "main" (func $main)))
diff --git a/tests/wasm_compile_block/test.v b/tests/wasm_compile_block/test.v
new file mode 120000
index 0000000..f0235d8
--- /dev/null
+++ b/tests/wasm_compile_block/test.v
@@ -0,0 +1 @@
+../wasm_compile_simple_module/test.v \ No newline at end of file
diff --git a/tests/wasm_compile_block/words_to_verify.mem b/tests/wasm_compile_block/words_to_verify.mem
new file mode 100644
index 0000000..c450cd6
--- /dev/null
+++ b/tests/wasm_compile_block/words_to_verify.mem
@@ -0,0 +1,7 @@
+// address value
+ 0FFFFC 23
+
+ 400 C
+ 404 6
+ 408 0
+ 40C F
diff --git a/tests/wasm_compile_br_if/words_to_verify.mem b/tests/wasm_compile_br_if/words_to_verify.mem
index aac1103..e7a45dc 100644
--- a/tests/wasm_compile_br_if/words_to_verify.mem
+++ b/tests/wasm_compile_br_if/words_to_verify.mem
@@ -1,6 +1,6 @@
// address value
0FFFFC 23
- 200 00000000
- 204 FFFFFFFF
- 208 FFFFFFFF
+ 400 00000000
+ 404 FFFFFFFF
+ 408 FFFFFFFF
diff --git a/tests/wasm_compile_function_call/words_to_verify.mem b/tests/wasm_compile_function_call/words_to_verify.mem
index bd24e95..a66822c 100644
--- a/tests/wasm_compile_function_call/words_to_verify.mem
+++ b/tests/wasm_compile_function_call/words_to_verify.mem
@@ -1,3 +1,4 @@
// address value
0FFFFC 23
- 23C 1E // Address is 0x200 + 0x25 + 0x17
+
+ 43C 1E // Address is 0x400 + 0x25 + 0x17
diff --git a/tests/wasm_compile_if_else/words_to_verify.mem b/tests/wasm_compile_if_else/words_to_verify.mem
index 75a6c84..22c6442 100644
--- a/tests/wasm_compile_if_else/words_to_verify.mem
+++ b/tests/wasm_compile_if_else/words_to_verify.mem
@@ -1,5 +1,5 @@
// address value
0FFFFC 23
- 200 00000000
- 204 FFFFFFFF
+ 400 00000000
+ 404 FFFFFFFF
diff --git a/tests/wasm_compile_loop/words_to_verify.mem b/tests/wasm_compile_loop/words_to_verify.mem
index ef41c69..43dba15 100644
--- a/tests/wasm_compile_loop/words_to_verify.mem
+++ b/tests/wasm_compile_loop/words_to_verify.mem
@@ -1,4 +1,4 @@
// address value
0FFFFC 23
- 200 00000037
+ 400 00000037
diff --git a/tests/wasm_compile_simple_module/test.v b/tests/wasm_compile_simple_module/test.v
index 5e28ba1..9a25ad9 100644
--- a/tests/wasm_compile_simple_module/test.v
+++ b/tests/wasm_compile_simple_module/test.v
@@ -159,7 +159,7 @@ module wasm_compile_test();
CLK <= 0;
RST <= 1;
- for (i = 0; i < 10000; i++) begin
+ for (i = 0; i < 20000; i++) begin
#1;
CLK <= ~CLK;
@@ -194,9 +194,9 @@ module wasm_compile_test();
$finish;
end // if (M_finished)
- end // for (i = 0; i < 10000; i++)
+ end // for (i = 0; i < 20000; i++)
- $display("error: cpu hasn't finished its operations in 5000 ticks");
+ $display("error: cpu hasn't finished its operations in 10000 ticks");
$finish;
end // initial begin
endmodule // stack_machine_test
diff --git a/tests/wasm_compile_simple_module/words_to_verify.mem b/tests/wasm_compile_simple_module/words_to_verify.mem
index d6a16c1..07046c4 100644
--- a/tests/wasm_compile_simple_module/words_to_verify.mem
+++ b/tests/wasm_compile_simple_module/words_to_verify.mem
@@ -1,3 +1,3 @@
// address value
0FFFFC 23
- 23C 1E // Address is 0x200 + 0x1F + 0x1D
+ 43C 1E // Address is 0x400 + 0x1F + 0x1D
diff --git a/tools/assemble.c b/tools/assemble.c
index b8bd75e..bb8c8d4 100644
--- a/tools/assemble.c
+++ b/tools/assemble.c
@@ -20,7 +20,7 @@ void free_expr(struct instruction *expr)
/* instructions are stored in a circular list */
int add_instruction(struct instruction **expr, uint16_t encoding,
- struct instruction_data data)
+ struct instruction_data data, const char *name)
{
struct instruction *new;
@@ -34,6 +34,7 @@ int add_instruction(struct instruction **expr, uint16_t encoding,
new->address_assigned = false;
new->encoding = encoding;
new->data = data;
+ new->name = name;
if (!*expr) {
new->next = new;
@@ -113,11 +114,13 @@ static uint16_t im_instruction(uint16_t payload)
}
static void encode_instruction(struct instruction *instruction,
- uint16_t *memory)
+ struct translated_word *memory)
{
uint32_t im = 0;
uint16_t encoding = instruction->encoding;
- uint16_t *dest = memory + instruction->address / 2;
+ struct translated_word *dest = memory + instruction->address / 2;
+
+ dest->instr = instruction;
if (instruction->data.info == DATA_INSTR_ADDR) {
im = (*instruction->data.data.ptr)->address;
@@ -132,17 +135,18 @@ static void encode_instruction(struct instruction *instruction,
case DATA_INSTR_ADDR :
case DATA_ADDR_AFTER :
case DATA_KNOWN :
- *(dest++) = im_instruction(im >> 22);
+ (dest++)->contents = im_instruction(im >> 22);
case DATA_KNOWN_21_BITS :
- *(dest++) = im_instruction(im >> 7);
+ (dest++)->contents = im_instruction(im >> 7);
case DATA_KNOWN_6_BITS :
encoding |= im & 0x7F;
}
- *dest = encoding;
+ dest->contents = encoding;
}
-static void encode_expr(struct instruction *expr, uint16_t *memory)
+static void encode_expr(struct instruction *expr,
+ struct translated_word *memory)
{
struct instruction *tmp = expr;
@@ -152,14 +156,14 @@ static void encode_expr(struct instruction *expr, uint16_t *memory)
} while (tmp != expr);
}
-int assemble(uint32_t memory_size, uint16_t memory[memory_size],
+int assemble(uint32_t memory_size, struct translated_word memory[memory_size],
struct module *module)
{
uint32_t i;
struct function *main_function = NULL;
uint32_t current_address;
uint64_t function_size;
- struct instruction *startup = NULL;
+ struct instruction **startup = &module->startup;
unsigned short startup_size;
int retval = -1;
@@ -181,13 +185,13 @@ int assemble(uint32_t memory_size, uint16_t memory[memory_size],
* We're first writing some value at STACK_FRAME_BACKUP_ADDR to be able
* to check, if the functions we call restore frame address properly
*/
- if (i_const(im(0x23), &startup) ||
- i_store(im(STACK_FRAME_BACKUP_ADDR), &startup) ||
- i_call (ptr(&main_function->translated_body), &startup) ||
- i_halt ( &startup))
+ if (i_const(im(0x23), startup) ||
+ i_store(im(STACK_FRAME_BACKUP_ADDR), startup) ||
+ i_call (ptr(&main_function->translated_body), startup) ||
+ i_halt ( startup))
goto fail;
- startup_size = estimate_expr_size(startup);
+ startup_size = estimate_expr_size(*startup);
i = module->functions_count;
current_address = CODE_TOP_ADDR;
@@ -209,13 +213,13 @@ int assemble(uint32_t memory_size, uint16_t memory[memory_size],
assign_addresses_and_sizes(module->functions[i].translated_body,
module->functions[i].start_addr);
- assign_addresses_and_sizes(startup, 0x0);
+ assign_addresses_and_sizes(*startup, 0x0);
i = module->functions_count;
while (i--)
encode_expr(module->functions[i].translated_body, memory);
- encode_expr(startup, memory);
+ encode_expr(*startup, memory);
retval = 0;
@@ -223,7 +227,5 @@ fail:
if (retval)
PRERR("Couldn't assemble code for stack machine\n");
- free_expr(startup);
-
return retval;
}
diff --git a/tools/parse_module.c b/tools/parse_module.c
index 3f9895c..8c519ab 100644
--- a/tools/parse_module.c
+++ b/tools/parse_module.c
@@ -84,6 +84,8 @@ void free_module(struct module *module)
free_targets(module->targets);
+ free_expr(module->startup);
+
free(module);
}
diff --git a/tools/stack_machine_instruction.h b/tools/stack_machine_instruction.h
index 1f47c40..15c870b 100644
--- a/tools/stack_machine_instruction.h
+++ b/tools/stack_machine_instruction.h
@@ -23,6 +23,7 @@ struct instruction {
bool address_assigned;
uint16_t encoding;
struct instruction_data data;
+ const char *name;
};
#define NO_DATA ((struct instruction_data) { \
@@ -76,21 +77,21 @@ inline static struct instruction_data ptr_after(struct instruction **val) {
}
int add_instruction(struct instruction **expr, uint16_t encoding,
- struct instruction_data data);
+ struct instruction_data data, const char *name);
/* Define stack machine instructions, that take immediate operands */
#define X(instr, encoding) \
inline static int i_##instr(struct instruction_data data, \
struct instruction **expr) \
{ \
- return add_instruction(expr, encoding, data); \
+ return add_instruction(expr, encoding, data, #instr); \
}
/* Define stack machine instructions, that *don't* take immediate operands */
#define Y(instr, encoding) \
inline static int i_##instr(struct instruction **expr) \
{ \
- return add_instruction(expr, encoding, NO_DATA); \
+ return add_instruction(expr, encoding, NO_DATA, #instr); \
}
X(store, 0x7E00) /* 0111_1110_0xxx_xxxx */
diff --git a/tools/translate.c b/tools/translate.c
index 27532ad..00191a3 100644
--- a/tools/translate.c
+++ b/tools/translate.c
@@ -276,7 +276,7 @@ static int typecheck_local_get_set(struct translation *data, uint32_t localidx,
/* Translate complex - those routines have to be defined manually */
#define TC(wasm_opcode, name, argtypes, restype)
-static int _translate_loop(struct translation *data)
+static int translate_block_loop(struct translation *data, bool loop)
{
struct resulttype block_args, block_results;
char type_storage;
@@ -291,7 +291,7 @@ static int _translate_loop(struct translation *data)
goto fail;
if (translate_expr(data, &block_args, &block_results,
- &loop_end_markers, NULL, true))
+ &loop_end_markers, NULL, loop))
goto fail;
return 0;
@@ -301,6 +301,16 @@ fail:
return -1;
}
+static int _translate_block(struct translation *data)
+{
+ return translate_block_loop(data, false);
+}
+
+static int _translate_loop(struct translation *data)
+{
+ return translate_block_loop(data, true);
+}
+
static int _translate_if(struct translation *data)
{
struct types *backed_stack;
@@ -343,7 +353,7 @@ static int _translate_if(struct translation *data)
data->types_stack = backed_stack;
if (retval)
- goto fail;
+ goto fail;
if (i_jump(ptr_after(&else_end->instr), expr))
goto fail;
@@ -422,7 +432,7 @@ static int _translate_br(struct translation *data)
i_load_p(im(-4 * (offset_dst - 1)), expr) ||
i_swap ( expr) ||
i_load_p(im(-4 * offset_dst), expr) ||
- i_add_sp(im(-4 * (shift + 2)), expr))
+ i_add_sp(im(4 * (shift + 2)), expr))
goto fail;
for (i = 0; i < arity; i++) {
@@ -615,11 +625,11 @@ static int translate_load_store(struct translation *data,
/** DEFINE TRANSLATION FUNCTIONS POINTER ARRAY **/
/* Translate complex */
-#define TC(wasm_opcode, name, argtypes, restype) \
+#define TC(wasm_opcode, name, argtypes, restype) \
[wasm_opcode] = _translate_##name,
/* Translate Simple */
-#define TS(wasm_opcode, sm_instr, argtypes, restype) \
+#define TS(wasm_opcode, sm_instr, argtypes, restype) \
TC(wasm_opcode, sm_instr, dummy, dummy)
/* Translate load/store */
@@ -734,6 +744,7 @@ static struct target *add_target(struct module *module)
}
static struct label *add_label(struct translation *data, struct target *target,
+ uint32_t values_popped,
struct resulttype *arity)
{
struct label *lbl;
@@ -750,6 +761,7 @@ static struct label *add_label(struct translation *data, struct target *target,
lbl->arity = arity;
lbl->values_on_stack = data->labels ? data->labels->values_on_stack : 0;
lbl->values_on_stack += stack_size(data->types_stack);
+ lbl->values_on_stack -= values_popped;
data->labels = lbl;
@@ -777,7 +789,7 @@ static int translate_expr(struct translation *data, struct resulttype *args,
if (continuation_at_start)
continuation->instr = data->function->translated_body->prev;
- label = add_label(data, continuation,
+ label = add_label(data, continuation, args ? args->count : 0,
continuation_at_start ? args : results);
if (!label)
@@ -918,9 +930,11 @@ int translate(FILE *handle, struct function *function, struct module *module)
goto fail;
/* function epilogue */
+ if (i_load (im(STACK_FRAME_BACKUP_ADDR), expr))
+ goto fail;
+
if (function->type->results.count) {
- if (i_load (im(STACK_FRAME_BACKUP_ADDR), expr) ||
- i_swap ( expr) ||
+ if (i_swap ( expr) ||
i_store_p(im(4 * (2 + all_locals_count - 1)), expr) ||
i_load (im(STACK_FRAME_BACKUP_ADDR), expr) ||
i_tee ( expr) ||
@@ -932,8 +946,7 @@ int translate(FILE *handle, struct function *function, struct module *module)
goto fail;
} else {
/* It's a bit shorter if we don't return anything */
- if (i_load (im(STACK_FRAME_BACKUP_ADDR), expr) ||
- i_tee ( expr) ||
+ if (i_tee ( expr) ||
i_tee ( expr) ||
i_load_p (im(4 * (1 + locals_count)), expr) ||
i_store_p(im(4 * (2 + all_locals_count - 1)), expr) ||
diff --git a/tools/translate_xmacro.h b/tools/translate_xmacro.h
index 079fc74..e906261 100644
--- a/tools/translate_xmacro.h
+++ b/tools/translate_xmacro.h
@@ -24,6 +24,7 @@ TLS(WASM_I32_STORE16, storew_p, i32_i32, empty)
* There are more checks to be performed in case of if and br_if, but we do them
* another way and only check for the i32 condition value here.
*/
+TC (WASM_BLOCK, block, custom, custom)
TC (WASM_LOOP, loop, custom, custom)
TC (WASM_IF, if, i32, custom)
TC (WASM_BR, br, custom, custom)
diff --git a/tools/wasm.h b/tools/wasm.h
index 8333ce5..afa1908 100644
--- a/tools/wasm.h
+++ b/tools/wasm.h
@@ -22,6 +22,7 @@
#define EXPORT_GLOBALIDX 0x03
/* WebAssembly opcodes */
+#define WASM_BLOCK 0x02
#define WASM_LOOP 0x03
#define WASM_IF 0x04
#define WASM_ELSE 0x05
diff --git a/tools/wasm_compile.c b/tools/wasm_compile.c
index 64988c8..c455541 100644
--- a/tools/wasm_compile.c
+++ b/tools/wasm_compile.c
@@ -1,24 +1,33 @@
#include "wasm_compile.h"
+#include "stack_machine_instruction.h"
-void print_instructions(uint32_t count, uint16_t instructions[count])
+void print_instructions(uint32_t count,
+ struct translated_word memory[count])
{
uint32_t i;
char binary[17];
- uint16_t instruction;
+ uint16_t bits;
int j;
binary[16] = '\0';
for (i = 0; i < count; i++) {
- instruction = instructions[i];
+ bits = memory[i].contents;
j = 16;
while (j--) {
- binary[j] = (instruction & 1) ? '1' : '0';
- instruction >>= 1;
+ binary[j] = (bits & 1) ? '1' : '0';
+ bits >>= 1;
}
- puts(binary);
+ printf(binary);
+
+ if (memory[i].instr) {
+ printf(" // 0x%03lx %s", (long) i,
+ memory[i].instr->name);
+ }
+
+ putchar('\n');
}
}
@@ -26,7 +35,7 @@ int main(int argc, char **argv)
{
FILE *handle = NULL;
struct module *module = NULL;
- uint16_t *translated_instructions = NULL;
+ struct translated_word *translated_instructions = NULL;
char retval = -1;
if (argc < 2) {
@@ -46,7 +55,8 @@ int main(int argc, char **argv)
if (!module)
goto fail;
- translated_instructions = calloc(1, CODE_TOP_ADDR);
+ translated_instructions = calloc(1, CODE_TOP_ADDR *
+ sizeof(struct translated_word));
if (!translated_instructions) {
PRERR(MSG_ALLOC_FAIL(CODE_TOP_ADDR));
diff --git a/tools/wasm_compile.h b/tools/wasm_compile.h
index 4cee1bb..c5ff49c 100644
--- a/tools/wasm_compile.h
+++ b/tools/wasm_compile.h
@@ -11,8 +11,8 @@
#define STACK_FRAME_BACKUP_ADDR 0x0FFFFC
#define STACK_TOP_ADDR 0x0FFFFC
#define CODE_BOTTOM_ADDR 0x000000
-#define CODE_TOP_ADDR 0x000200
-#define MEMORY_BOTTOM_ADDR 0x000200
+#define CODE_TOP_ADDR 0x000400
+#define MEMORY_BOTTOM_ADDR 0x000400
/* Error messages */
#define MSG_SIZE_OVERFLOW "Number overflows size_t\n"
@@ -70,6 +70,12 @@ struct module {
uint32_t exports_count;
struct export *exports;
struct target *targets;
+ struct instruction *startup;
+};
+
+struct translated_word {
+ uint16_t contents;
+ struct instruction *instr;
};
int leb_32(FILE *handle, uint32_t *result, bool with_sign);
@@ -94,7 +100,7 @@ struct module *parse_module(FILE *handle);
int translate(FILE *handle, struct function *function, struct module *module);
-int assemble(uint32_t memory_size, uint16_t memory[memory_size],
+int assemble(uint32_t memory_size, struct translated_word memory[memory_size],
struct module *module);
#endif /* WASM_COMPILE_H */