From 63a2cced4238af7d171e0b8807d887c435b4656b Mon Sep 17 00:00:00 2001 From: Wojciech Kosior Date: Tue, 6 Oct 2020 18:49:05 +0200 Subject: add translation of relational operations and loops --- tests/wasm_compile_loop/Makefile | 1 + tests/wasm_compile_loop/instructions.wat | 25 ++++++++++ tests/wasm_compile_loop/test.v | 1 + tests/wasm_compile_loop/words_to_verify.mem | 4 ++ tools/stack_machine_instruction.h | 48 ++++--------------- tools/translate.c | 74 +++++++++++++++++++++-------- tools/translate_xmacro.h | 7 +++ tools/wasm.h | 12 +++++ 8 files changed, 114 insertions(+), 58 deletions(-) create mode 120000 tests/wasm_compile_loop/Makefile create mode 100644 tests/wasm_compile_loop/instructions.wat create mode 120000 tests/wasm_compile_loop/test.v create mode 100644 tests/wasm_compile_loop/words_to_verify.mem diff --git a/tests/wasm_compile_loop/Makefile b/tests/wasm_compile_loop/Makefile new file mode 120000 index 0000000..e451c8b --- /dev/null +++ b/tests/wasm_compile_loop/Makefile @@ -0,0 +1 @@ +../wasm_compile_simple_module/Makefile \ No newline at end of file diff --git a/tests/wasm_compile_loop/instructions.wat b/tests/wasm_compile_loop/instructions.wat new file mode 100644 index 0000000..02a75e0 --- /dev/null +++ b/tests/wasm_compile_loop/instructions.wat @@ -0,0 +1,25 @@ +(module + (memory 0 2) + (func $main + (local $counter i32) + + ;; prepare offset for store operation later + (i32.const 0x0) + + ;; initialize counter + (set_local $counter (i32.const 0)) + + ;; add numbers from 1 to 10 + (i32.const 0) + (loop $again (param i32) (result i32) + (set_local $counter (i32.add + (get_local $counter) + (i32.const 1))) + (i32.add (get_local $counter)) + (br_if $again (i32.lt_u + (get_local $counter) + (i32.const 10)))) + + ;; write computed sum (55 in dec, 37 in hex) at MEMORY_BOTTOM_ADDR + (i32.store offset=0x0 align=2)) + (export "main" (func $main))) diff --git a/tests/wasm_compile_loop/test.v b/tests/wasm_compile_loop/test.v new file mode 120000 index 0000000..f0235d8 --- /dev/null +++ b/tests/wasm_compile_loop/test.v @@ -0,0 +1 @@ +../wasm_compile_simple_module/test.v \ No newline at end of file diff --git a/tests/wasm_compile_loop/words_to_verify.mem b/tests/wasm_compile_loop/words_to_verify.mem new file mode 100644 index 0000000..ef41c69 --- /dev/null +++ b/tests/wasm_compile_loop/words_to_verify.mem @@ -0,0 +1,4 @@ +// address value + 0FFFFC 23 + + 200 00000037 diff --git a/tools/stack_machine_instruction.h b/tools/stack_machine_instruction.h index 003fa19..1f47c40 100644 --- a/tools/stack_machine_instruction.h +++ b/tools/stack_machine_instruction.h @@ -2,45 +2,6 @@ #include "wasm_compile.h" -/* - * TODO: this enum is to be removed; it it only still here as a cheat sheet - * for use when defining missing inline functions for those instructions - */ -enum instruction_code { - STORE, - STORE_P, - STOREB, - STOREB_P, - STOREW, - STOREW_P, - LOAD, - LOAD_P, - LOADBZX, - LOADBZX_P, - LOADBSX, - LOADBSX_P, - LOADWZX, - LOADWZX_P, - LOADWSX, - LOADWSX_P, - HALT, - NOP, - SWAP, - SET_SP, - JUMP, - TEE, - GET_FRAME, - CONST, - CALL, - ADD, - SUB, - DIV, - MUL, - DROP, - RET, - COND_JUMP -}; - #define DATA_NONE 0 #define DATA_KNOWN 1 #define DATA_KNOWN_21_BITS 2 @@ -156,6 +117,15 @@ Y(sub, 0x3001) /* 0011_0000_0000_0001 */ Y(div, 0x3002) /* 0011_0000_0000_0010 */ Y(mul, 0x3003) /* 0011_0000_0000_0011 */ Y(drop, 0x3004) /* 0011_0000_0000_0100 */ +Y(eq, 0x3007) /* 0011_0000_0000_0111 */ +Y(lt, 0x3008) /* 0011_0000_0000_1000 */ +Y(ult, 0x3009) /* 0011_0000_0000_1001 */ +Y(le, 0x300A) /* 0011_0000_0000_1010 */ +Y(ule, 0x300B) /* 0011_0000_0000_1011 */ +Y(gt, 0x300C) /* 0011_0000_0000_1100 */ +Y(ugt, 0x300D) /* 0011_0000_0000_1101 */ +Y(ge, 0x300E) /* 0011_0000_0000_1110 */ +Y(uge, 0x300F) /* 0011_0000_0000_1111 */ Y(ret, 0x3080) /* 0011_0000_1000_0000 */ X(cond_jump, 0x7080) /* 0111_0000_1xxx_xxxx */ X(cond_jump_n, 0x7100) /* 0111_0001_0xxx_xxxx */ diff --git a/tools/translate.c b/tools/translate.c index 8b28aad..27532ad 100644 --- a/tools/translate.c +++ b/tools/translate.c @@ -259,17 +259,16 @@ static int typecheck_call(struct translation *data, struct function *callee) return 0; } -static int typecheck_local_get(struct translation *data, uint32_t localidx) +static int typecheck_local_get_set(struct translation *data, uint32_t localidx, + bool set) { uint32_t args_count = data->function->type->args.count; char type = localidx < args_count ? data->function->type->args.types[localidx] : data->function->locals[localidx - args_count]; - if (rescheck_generic(&data->types_stack, type)) - return -1; - - return 0; + return (set ? argcheck_generic : rescheck_generic) + (&data->types_stack, type); } /** DEFINE INSTRUCTION TRANSLATION FUNCTIONS **/ @@ -277,6 +276,31 @@ static int typecheck_local_get(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) +{ + struct resulttype block_args, block_results; + char type_storage; + static const uint8_t loop_end_marker_code = WASM_END; + static const struct end_markers loop_end_markers = { + .count = 1, + .codes = &loop_end_marker_code + }; + + if (parse_blocktype(data->handle, &block_args, &block_results, + &type_storage, data->module)) + goto fail; + + if (translate_expr(data, &block_args, &block_results, + &loop_end_markers, NULL, true)) + goto fail; + + return 0; + +fail: + PRERR("Couldn't translate loop instruction\n"); + return -1; +} + static int _translate_if(struct translation *data) { struct types *backed_stack; @@ -488,9 +512,7 @@ static int _translate_call(struct translation *data) return i_call(ptr(target), &data->function->translated_body); } -static int typecheck_local_get(struct translation *data, uint32_t localidx); - -static int _translate_local_get(struct translation *data) +static int translate_local_get_set(struct translation *data, bool set) { uint32_t localidx; uint32_t args_count = data->function->type->args.count; @@ -509,7 +531,7 @@ static int _translate_local_get(struct translation *data) return -1; } - if (typecheck_local_get(data, localidx)) + if (typecheck_local_get_set(data, localidx, set)) return -1; offset_on_frame = all_locals_count - localidx + 1; @@ -517,11 +539,27 @@ static int _translate_local_get(struct translation *data) if (localidx >= args_count) offset_on_frame -= 1; - if (i_load (im(STACK_FRAME_BACKUP_ADDR), expr) || - i_load_p(im(4 * offset_on_frame), expr)) + if (i_load(im(STACK_FRAME_BACKUP_ADDR), expr)) return -1; - return 0; + if (set) { + return + i_swap ( expr) || + i_store_p(im(4 * offset_on_frame), expr); + } else { + return + i_load_p(im(4 * offset_on_frame), expr); + } +} + +static int _translate_local_get(struct translation *data) +{ + return translate_local_get_set(data, false); +} + +static int _translate_local_set(struct translation *data) +{ + return translate_local_get_set(data, true); } static int _translate_const(struct translation *data) @@ -610,12 +648,10 @@ static int translate_instr(struct translation *data, uint8_t wasm_opcode) tc_routines = typecheck_routines + wasm_opcode; - if (tc_routines->argcheck(&data->types_stack) || - tc_routines->rescheck(&data->types_stack) || - translation_routines[wasm_opcode](data)) - return -1; - - return 0; + return + tc_routines->argcheck(&data->types_stack) || + translation_routines[wasm_opcode](data) || + tc_routines->rescheck(&data->types_stack); } static int parse_blocktype(FILE *handle, struct resulttype *args, @@ -666,7 +702,7 @@ static int parse_blocktype(FILE *handle, struct resulttype *args, goto fail; } - if (typeidx <= module->functypes_count) { + if (typeidx >= module->functypes_count) { PRERR(MSG_BAD_IDX("type index")); goto fail; } diff --git a/tools/translate_xmacro.h b/tools/translate_xmacro.h index 958d8d9..079fc74 100644 --- a/tools/translate_xmacro.h +++ b/tools/translate_xmacro.h @@ -5,6 +5,11 @@ TS (WASM_I32_ADD, add, i32_i32, i32) TS (WASM_I32_SUB, sub, i32_i32, i32) TS (WASM_I32_DIV_U, div, i32_i32, i32) TS (WASM_I32_MUL, mul, i32_i32, i32) +TS (WASM_I32_EQ, eq, i32_i32, i32) +TS (WASM_I32_LT_S, lt, i32_i32, i32) +TS (WASM_I32_LT_U, ult, i32_i32, i32) +TS (WASM_I32_GT_S, gt, i32_i32, i32) +TS (WASM_I32_GT_U, ugt, i32_i32, i32) TLS(WASM_I32_LOAD, load_p, i32, i32) TLS(WASM_I32_LOAD8_S, loadbsx_p, i32, i32) @@ -19,9 +24,11 @@ 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_LOOP, loop, custom, custom) TC (WASM_IF, if, i32, custom) TC (WASM_BR, br, custom, custom) TC (WASM_BR_IF, br_if, i32, custom) TC (WASM_CALL, call, custom, custom) TC (WASM_LOCAL_GET, local_get, empty, custom) +TC (WASM_LOCAL_SET, local_set, custom, empty) TC (WASM_I32_CONST, const, empty, i32) diff --git a/tools/wasm.h b/tools/wasm.h index 476f892..8333ce5 100644 --- a/tools/wasm.h +++ b/tools/wasm.h @@ -22,6 +22,7 @@ #define EXPORT_GLOBALIDX 0x03 /* WebAssembly opcodes */ +#define WASM_LOOP 0x03 #define WASM_IF 0x04 #define WASM_ELSE 0x05 #define WASM_END 0x0B @@ -30,6 +31,7 @@ #define WASM_CALL 0x10 #define WASM_LOCAL_GET 0x20 +#define WASM_LOCAL_SET 0x21 #define WASM_I32_LOAD 0x28 #define WASM_I32_LOAD8_S 0x2C @@ -43,6 +45,16 @@ #define WASM_I32_CONST 0x41 +#define WASM_I32_EQ 0x46 +#define WASM_I32_LT_S 0x48 +#define WASM_I32_LT_U 0x49 +#define WASM_I32_GT_S 0x4A +#define WASM_I32_GT_U 0x4B +#define WASM_I32_LE_S 0x4C +#define WASM_I32_LE_U 0x4D +#define WASM_I32_GE_S 0x4E +#define WASM_I32_GE_U 0x4F + #define WASM_I32_ADD 0x6A #define WASM_I32_SUB 0x6B #define WASM_I32_MUL 0x6C -- cgit v1.2.3