added alternative implementation for memory copy/fill for unsupporting WASM engines
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 4 Feb 2021 00:25:43 +0000 (18:25 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 4 Feb 2021 00:25:43 +0000 (18:25 -0600)
bin/onyx
bin/test
include/onyxastnodes.h
onyx.exe
src/onyx.c
src/onyxwasm.c
src/onyxwasm_intrinsics.c [new file with mode: 0644]

index 732de5b6931f0c46f1d209ec4e61261294e19acf..684526469291386e579e35316863a19f99caac77 100755 (executable)
Binary files a/bin/onyx and b/bin/onyx differ
index ad67c6fa7ac0383a034618764c4fd2ebcfe23e64..59bef9158a5330ba9ae83dc7411e38a1dc8b471b 100755 (executable)
--- 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
index 32fec4ec06bd4e14bacd5fea08b4e78f4e2ccc78..e27854ac0cb9ccdd8ce71a30dc7734273d537882 100644 (file)
@@ -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;
index 1c6e84522261ca419a1856de24b869b03fffc947..5f5be401eb678c65e012b5bcfb50b1f3d9b4d702 100644 (file)
Binary files a/onyx.exe and b/onyx.exe differ
index a01a38ae36d9c383e5034a3c4014d9e97d09b533..f796c3ffe3873774c03707bd3f627e334aac3466 100644 (file)
@@ -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]);
             }
index 18e384a9c228dc01677e67c4b5c144e6eb8c5538..2c9ae07db2f80e5dd3d9ef3c3d2c10dea4a03bcd 100644 (file)
@@ -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 (file)
index 0000000..cd4ac9a
--- /dev/null
@@ -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:
+    //     <count>
+    //     <source>
+    //     <dest>
+    
+    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:
+    //     <count>
+    //     <byte>
+    //     <dest>
+    
+    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