From 5e04a9626e2986fc40825d15cb09a274223381e9 Mon Sep 17 00:00:00 2001 From: Wojciech Kosior Date: Thu, 8 Oct 2020 19:18:43 +0200 Subject: translate webasm block of instructions + put instruction names as comments in generated code --- tests/wasm_compile_arithm/words_to_verify.mem | 8 +- tests/wasm_compile_block/Makefile | 1 + tests/wasm_compile_block/instructions.wat | 121 +++++++++++++++++++++ tests/wasm_compile_block/test.v | 1 + tests/wasm_compile_block/words_to_verify.mem | 7 ++ tests/wasm_compile_br_if/words_to_verify.mem | 6 +- .../wasm_compile_function_call/words_to_verify.mem | 3 +- tests/wasm_compile_if_else/words_to_verify.mem | 4 +- tests/wasm_compile_loop/words_to_verify.mem | 2 +- tests/wasm_compile_simple_module/test.v | 6 +- .../wasm_compile_simple_module/words_to_verify.mem | 2 +- tools/assemble.c | 38 ++++--- tools/parse_module.c | 2 + tools/stack_machine_instruction.h | 7 +- tools/translate.c | 35 ++++-- tools/translate_xmacro.h | 1 + tools/wasm.h | 1 + tools/wasm_compile.c | 26 +++-- tools/wasm_compile.h | 12 +- 19 files changed, 225 insertions(+), 58 deletions(-) create mode 120000 tests/wasm_compile_block/Makefile create mode 100644 tests/wasm_compile_block/instructions.wat create mode 120000 tests/wasm_compile_block/test.v create mode 100644 tests/wasm_compile_block/words_to_verify.mem 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 */ -- cgit v1.2.3