From: Brendan Hansen Date: Thu, 4 Feb 2021 00:25:43 +0000 (-0600) Subject: added alternative implementation for memory copy/fill for unsupporting WASM engines X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=3d640dee18e4a309e22b543aaad6bb9a16d229c3;p=onyx.git added alternative implementation for memory copy/fill for unsupporting WASM engines --- diff --git a/bin/onyx b/bin/onyx index 732de5b6..68452646 100755 Binary files a/bin/onyx and b/bin/onyx differ diff --git a/bin/test b/bin/test index ad67c6fa..59bef915 100755 --- a/bin/test +++ b/bin/test @@ -16,7 +16,7 @@ for test_file in $(find tests/ -name '*.onyx'); do print_check "$name" - if ! ./bin/onyx "$test_file" -o "./tests/$name.wasm" >/dev/null; then + if ! ./bin/onyx --use-post-mvp-features "$test_file" -o "./tests/$name.wasm" >/dev/null; then print "\n❌ Failed to compile $name.onyx.\n" failed=1 continue diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index 32fec4ec..e27854ac 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -960,9 +960,11 @@ struct CompileOptions { bh_allocator allocator; CompileAction action; - u32 verbose_output : 30; + u32 verbose_output : 29; b32 fun_output : 1; - b32 print_function_mappings : 1; + b32 print_function_mappings : 1; + + b32 use_post_mvp_features : 1; bh_arr(const char *) included_folders; bh_arr(const char *) files; diff --git a/onyx.exe b/onyx.exe index 1c6e8452..5f5be401 100644 Binary files a/onyx.exe and b/onyx.exe differ diff --git a/src/onyx.c b/src/onyx.c index a01a38ae..f796c3ff 100644 --- a/src/onyx.c +++ b/src/onyx.c @@ -48,6 +48,7 @@ static CompileOptions compile_opts_parse(bh_allocator alloc, int argc, char *arg .verbose_output = 0, .fun_output = 0, .print_function_mappings = 0, + .use_post_mvp_features = 0, .files = NULL, .target_file = "out.wasm", @@ -85,6 +86,9 @@ static CompileOptions compile_opts_parse(bh_allocator alloc, int argc, char *arg else if (!strcmp(argv[i], "--print-function-mappings")) { options.print_function_mappings = 1; } + else if (!strcmp(argv[i], "--use-post-mvp-features")) { + options.use_post_mvp_features = 1; + } else if (!strcmp(argv[i], "-I")) { bh_arr_push(options.included_folders, argv[++i]); } diff --git a/src/onyxwasm.c b/src/onyxwasm.c index 18e384a9..2c9ae07d 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -252,6 +252,8 @@ EMIT_FUNC(stack_leave, u32 unused); EMIT_FUNC(enter_structured_block, StructuredBlockType sbt); EMIT_FUNC_NO_ARGS(leave_structured_block); +#include "onyxwasm_intrinsics.c" + EMIT_FUNC(function_body, AstFunction* fd) { if (fd->body == NULL) return; @@ -1398,8 +1400,20 @@ EMIT_FUNC(intrinsic_call, AstCall* call) { switch (call->intrinsic) { case ONYX_INTRINSIC_MEMORY_SIZE: WID(WI_MEMORY_SIZE, 0x00); break; case ONYX_INTRINSIC_MEMORY_GROW: WID(WI_MEMORY_GROW, 0x00); break; - case ONYX_INTRINSIC_MEMORY_COPY: WIL(WI_MEMORY_COPY, 0x00); break; - case ONYX_INTRINSIC_MEMORY_FILL: WID(WI_MEMORY_FILL, 0x00); break; + case ONYX_INTRINSIC_MEMORY_COPY: + if (context.options->use_post_mvp_features) { + WIL(WI_MEMORY_COPY, 0x00); + } else { + emit_intrinsic_memory_copy(mod, &code); + } + break; + case ONYX_INTRINSIC_MEMORY_FILL: + if (context.options->use_post_mvp_features) { + WIL(WI_MEMORY_FILL, 0x00); + } else { + emit_intrinsic_memory_fill(mod, &code); + } + break; case ONYX_INTRINSIC_I32_CLZ: WI(WI_I32_CLZ); break; case ONYX_INTRINSIC_I32_CTZ: WI(WI_I32_CTZ); break; diff --git a/src/onyxwasm_intrinsics.c b/src/onyxwasm_intrinsics.c new file mode 100644 index 00000000..cd4ac9a2 --- /dev/null +++ b/src/onyxwasm_intrinsics.c @@ -0,0 +1,114 @@ +// This file is directly included in onxywasm. +// It is here purely to decrease the amount of clutter in the main file. + + +// IMPROVE: This implementation assumes that the source and destination buffers do not overlap. +// The specification for memory.copy in WASM does work even in the buffers overlap. +// Also, this implementation copies byte-by-byte, which is terrible. It should copy +// quad word by quad word, and then the additional bytes if the count was not divisible by 8. +// :32BitPointers +EMIT_FUNC_NO_ARGS(intrinsic_memory_copy) { + bh_arr(WasmInstruction) code = *pcode; + + // The stack should look like this: + // + // + // + + u64 count_local = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32); + u64 source_local = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32); + u64 dest_local = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32); + + WIL(WI_LOCAL_SET, count_local); + WIL(WI_LOCAL_SET, source_local); + WIL(WI_LOCAL_SET, dest_local); + + // count is greater than 0 + WIL(WI_LOCAL_GET, count_local); + WID(WI_I32_CONST, 0); + WI(WI_I32_GT_S); + + WID(WI_IF_START, 0x40); + WID(WI_LOOP_START, 0x40); + + WIL(WI_LOCAL_GET, count_local); + WID(WI_I32_CONST, 1); + WI(WI_I32_SUB); + WIL(WI_LOCAL_SET, count_local); + + WIL(WI_LOCAL_GET, dest_local); + WIL(WI_LOCAL_GET, count_local); + WI(WI_I32_ADD); + + WIL(WI_LOCAL_GET, source_local); + WIL(WI_LOCAL_GET, count_local); + WI(WI_I32_ADD); + + WID(WI_I32_LOAD_8_U, ((WasmInstructionData) { 0, 0 })); + WID(WI_I32_STORE_8, ((WasmInstructionData) { 0, 0 })); + + WIL(WI_LOCAL_GET, count_local); + WID(WI_I32_CONST, 0); + WI(WI_I32_GT_S); + WID(WI_COND_JUMP, 0x00); + + WI(WI_LOOP_END); + WI(WI_IF_END); + + local_raw_free(mod->local_alloc, WASM_TYPE_INT32); + local_raw_free(mod->local_alloc, WASM_TYPE_INT32); + local_raw_free(mod->local_alloc, WASM_TYPE_INT32); + + *pcode = code; +} + +EMIT_FUNC_NO_ARGS(intrinsic_memory_fill) { + bh_arr(WasmInstruction) code = *pcode; + + // The stack should look like this: + // + // + // + + u64 count_local = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32); + u64 byte_local = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32); + u64 dest_local = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32); + + WIL(WI_LOCAL_SET, count_local); + WIL(WI_LOCAL_SET, byte_local); + WIL(WI_LOCAL_SET, dest_local); + + // count is greater than 0 + WIL(WI_LOCAL_GET, count_local); + WID(WI_I32_CONST, 0); + WI(WI_I32_GT_S); + + WID(WI_IF_START, 0x40); + WID(WI_LOOP_START, 0x40); + + WIL(WI_LOCAL_GET, count_local); + WID(WI_I32_CONST, 1); + WI(WI_I32_SUB); + WIL(WI_LOCAL_SET, count_local); + + WIL(WI_LOCAL_GET, dest_local); + WIL(WI_LOCAL_GET, count_local); + WI(WI_I32_ADD); + + WIL(WI_LOCAL_GET, byte_local); + WID(WI_I32_STORE_8, ((WasmInstructionData) { 0, 0 })); + + WIL(WI_LOCAL_GET, count_local); + WID(WI_I32_CONST, 0); + WI(WI_I32_GT_S); + WID(WI_COND_JUMP, 0x00); + + WI(WI_LOOP_END); + WI(WI_IF_END); + + local_raw_free(mod->local_alloc, WASM_TYPE_INT32); + local_raw_free(mod->local_alloc, WASM_TYPE_INT32); + local_raw_free(mod->local_alloc, WASM_TYPE_INT32); + + *pcode = code; +} \ No newline at end of file