From: Brendan Hansen Date: Sat, 25 Jun 2022 23:10:44 +0000 (-0500) Subject: almost all MVP instructions can be parsed and compiled X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=2d0e6c246d60164cc0f1379645612fc9fb5474aa;p=onyx-embedder.git almost all MVP instructions can be parsed and compiled --- diff --git a/include/onyx_wasm.h b/include/onyx_wasm.h index b42b8ba..eae8c3d 100644 --- a/include/onyx_wasm.h +++ b/include/onyx_wasm.h @@ -127,7 +127,7 @@ struct wasm_module_t { struct wasm_func_inner_t { wasm_instance_t *instance; - ovm_func_t *func; + i32 func_idx; wasm_functype_t *type; }; diff --git a/include/vm.h b/include/vm.h index f777423..2b5157b 100644 --- a/include/vm.h +++ b/include/vm.h @@ -247,10 +247,9 @@ struct ovm_instr_t { #define OVMI_AND 0x08 // %r = %a & %b #define OVMI_OR 0x09 // %r = %a | %b #define OVMI_XOR 0x0A // %r = %a ^ %b -#define OVMI_NOT 0x0B // %r = ~%a // This one might not be needed, as WASM doesn't provide it -#define OVMI_SHL 0x0C // %r = %a << %b -#define OVMI_SHR 0x0D // %r = %a >> %b -#define OVMI_SAR 0x0E // %r = %a >>> %b +#define OVMI_SHL 0x0B // %r = %a << %b +#define OVMI_SHR 0x0C // %r = %a >> %b +#define OVMI_SAR 0x0D // %r = %a >>> %b #define OVMI_IMM 0x10 // %r = i/l/f/d #define OVMI_MOV 0x10 // %r = %a diff --git a/include/vm_codebuilder.h b/include/vm_codebuilder.h index 5d93b7a..cd078d0 100644 --- a/include/vm_codebuilder.h +++ b/include/vm_codebuilder.h @@ -62,5 +62,7 @@ void ovm_code_builder_add_register_get(ovm_code_builder_t *builder void ovm_code_builder_add_register_set(ovm_code_builder_t *builder, i32 local_idx); void ovm_code_builder_add_load(ovm_code_builder_t *builder, u32 ovm_type, i32 offset); void ovm_code_builder_add_store(ovm_code_builder_t *builder, u32 ovm_type, i32 offset); +void ovm_code_builder_add_memory_copy(ovm_code_builder_t *builder); +void ovm_code_builder_add_memory_fill(ovm_code_builder_t *builder); #endif diff --git a/src/vm/code_builder.c b/src/vm/code_builder.c index 43ce2b9..3701078 100644 --- a/src/vm/code_builder.c +++ b/src/vm/code_builder.c @@ -3,13 +3,17 @@ #define PUSH_VALUE(b, r) (bh_arr_push((b)->execution_stack, r)) #define POP_VALUE(b) (bh_arr_length((b)->execution_stack) == 0 ? (assert(("invalid value pop", 0)), 0) : bh_arr_pop((b)->execution_stack)) -#define NEXT_VALUE(b) (bh_arr_length((b)->execution_stack) == 0 ? \ - (b)->param_count + (b)->local_count : \ - ((b)->highest_value_number = bh_max((b)->highest_value_number, bh_arr_last((b)->execution_stack)), \ - bh_arr_last((b)->execution_stack) + 1)) - // #define POP_VALUE(b) bh_arr_pop((b)->execution_stack) +static inline int NEXT_VALUE(ovm_code_builder_t *b) { + if (bh_arr_length(b->execution_stack) == 0) { + return b->param_count + b->local_count; + } + + b->highest_value_number = bh_max(b->highest_value_number, bh_arr_last(b->execution_stack)); + return bh_arr_last(b->execution_stack) + 1; +} + ovm_code_builder_t ovm_code_builder_new(ovm_program_t *program, i32 param_count, i32 local_count) { ovm_code_builder_t builder; builder.param_count = param_count; @@ -300,3 +304,22 @@ void ovm_code_builder_add_store(ovm_code_builder_t *builder, u32 ovm_type, i32 o ovm_program_add_instructions(builder->program, 3, instrs); } +void ovm_code_builder_add_memory_copy(ovm_code_builder_t *builder) { + ovm_instr_t instr = {0}; + instr.full_instr = OVMI_COPY; + instr.b = POP_VALUE(builder); + instr.a = POP_VALUE(builder); + instr.r = POP_VALUE(builder); + + ovm_program_add_instructions(builder->program, 1, &instr); +} + +void ovm_code_builder_add_memory_fill(ovm_code_builder_t *builder) { + ovm_instr_t instr = {0}; + instr.full_instr = OVMI_FILL; + instr.b = POP_VALUE(builder); + instr.a = POP_VALUE(builder); + instr.r = POP_VALUE(builder); + + ovm_program_add_instructions(builder->program, 1, &instr); +} diff --git a/src/vm/vm.c b/src/vm/vm.c index 00eea16..3ef3af1 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -154,11 +154,6 @@ static char *ovm_instr_name(i32 full_instr) { C(OVM_TYPED_INSTR(OVMI_XOR, OVM_TYPE_I32)) C(OVM_TYPED_INSTR(OVMI_XOR, OVM_TYPE_I64)) - C(OVM_TYPED_INSTR(OVMI_NOT, OVM_TYPE_I8)) - C(OVM_TYPED_INSTR(OVMI_NOT, OVM_TYPE_I16)) - C(OVM_TYPED_INSTR(OVMI_NOT, OVM_TYPE_I32)) - C(OVM_TYPED_INSTR(OVMI_NOT, OVM_TYPE_I64)) - C(OVM_TYPED_INSTR(OVMI_SHL, OVM_TYPE_I8)) C(OVM_TYPED_INSTR(OVMI_SHL, OVM_TYPE_I16)) C(OVM_TYPED_INSTR(OVMI_SHL, OVM_TYPE_I32)) @@ -368,7 +363,7 @@ void ovm_program_print_instructions(ovm_program_t *program, i32 start_instr, i32 // is the start of a function, but for now, it'll do. -brendanfh 06/13/2022 bh_arr_each(ovm_func_t, func, program->funcs) { if (i == func->start_instr && func->kind == OVM_FUNC_INTERNAL) { - printf("\n[%d]%s:\n", func->id, func->name); + printf("\n[%d] %s values=%d:\n", func->id, func->name, func->value_number_count); } } @@ -660,11 +655,6 @@ void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *progr VAL(instr.r).type = t; \ VAL(instr.r).ctype = (ctype) op (VAL(instr.a).ctype); \ break; - - OVM_OP(OVMI_NOT, OVM_TYPE_I8 , ~, i8) - OVM_OP(OVMI_NOT, OVM_TYPE_I16, ~, i16) - OVM_OP(OVMI_NOT, OVM_TYPE_I32, ~, i32) - OVM_OP(OVMI_NOT, OVM_TYPE_I64, ~, i64) OVM_OP(OVMI_CLZ, OVM_TYPE_I8 , __builtin_clz, i8) OVM_OP(OVMI_CLZ, OVM_TYPE_I16, __builtin_clz, i16) diff --git a/src/wasm/module_parsing.c.incl b/src/wasm/module_parsing.c.incl index ead2221..2ee8941 100644 --- a/src/wasm/module_parsing.c.incl +++ b/src/wasm/module_parsing.c.incl @@ -385,9 +385,53 @@ static void pop_label_target(build_context *ctx) { static void parse_expression(build_context *ctx); +static void parse_fc_instruction(build_context *ctx) { + int instr_num = uleb128_to_uint(ctx->binary.data, &ctx->offset); + + switch (instr_num) { + case 0: ovm_code_builder_add_unop (&ctx->builder, OVM_TYPED_INSTR(OVMI_CVT_F32, OVM_TYPE_I32)); break; + case 1: ovm_code_builder_add_unop (&ctx->builder, OVM_TYPED_INSTR(OVMI_CVT_F32, OVM_TYPE_I32)); break; + case 2: ovm_code_builder_add_unop (&ctx->builder, OVM_TYPED_INSTR(OVMI_CVT_F64, OVM_TYPE_I32)); break; + case 3: ovm_code_builder_add_unop (&ctx->builder, OVM_TYPED_INSTR(OVMI_CVT_F64, OVM_TYPE_I32)); break; + case 4: ovm_code_builder_add_unop (&ctx->builder, OVM_TYPED_INSTR(OVMI_CVT_F32, OVM_TYPE_I64)); break; + case 5: ovm_code_builder_add_unop (&ctx->builder, OVM_TYPED_INSTR(OVMI_CVT_F32, OVM_TYPE_I64)); break; + case 6: ovm_code_builder_add_unop (&ctx->builder, OVM_TYPED_INSTR(OVMI_CVT_F64, OVM_TYPE_I64)); break; + case 7: ovm_code_builder_add_unop (&ctx->builder, OVM_TYPED_INSTR(OVMI_CVT_F64, OVM_TYPE_I64)); break; + + case 8: { + int dataidx = uleb128_to_uint(ctx->binary.data, &ctx->offset); + assert(CONSUME_BYTE(ctx) == 0x00); + + ovm_code_builder_drop_value(&ctx->builder); + ovm_code_builder_drop_value(&ctx->builder); + ovm_code_builder_drop_value(&ctx->builder); + + // TODO: MEMORY INIT INSTRUCTION + break; + } + + case 10: { + assert(CONSUME_BYTE(ctx) == 0x00); + assert(CONSUME_BYTE(ctx) == 0x00); + + ovm_code_builder_add_memory_copy(&ctx->builder); + break; + } + + case 11: { + assert(CONSUME_BYTE(ctx) == 0x00); + + ovm_code_builder_add_memory_fill(&ctx->builder); + break; + } + + default: assert(("UNHANDLED FC INSTRUCTION", 0)); + } +} + static void parse_instruction(build_context *ctx) { - unsigned char instr_byte; - switch (instr_byte = CONSUME_BYTE(ctx)) { + unsigned char instr_byte = CONSUME_BYTE(ctx); + switch (instr_byte) { case 0x00: break; case 0x01: break; case 0x02: { @@ -522,61 +566,62 @@ static void parse_instruction(build_context *ctx) { break; } - case 0x28: { - int alignment = uleb128_to_uint(ctx->binary.data, &ctx->offset); - int offset = uleb128_to_uint(ctx->binary.data, &ctx->offset); - ovm_code_builder_add_load(&ctx->builder, OVM_TYPE_I32, offset); - break; +#define LOAD_CASE(num, type) \ + case num : { \ + int alignment = uleb128_to_uint(ctx->binary.data, &ctx->offset); \ + int offset = uleb128_to_uint(ctx->binary.data, &ctx->offset); \ + ovm_code_builder_add_load(&ctx->builder, type, offset); \ + break; \ } - case 0x29: { - int alignment = uleb128_to_uint(ctx->binary.data, &ctx->offset); - int offset = uleb128_to_uint(ctx->binary.data, &ctx->offset); - ovm_code_builder_add_load(&ctx->builder, OVM_TYPE_I64, offset); - break; - } + LOAD_CASE(0x28, OVM_TYPE_I32) + LOAD_CASE(0x29, OVM_TYPE_I64) + LOAD_CASE(0x2A, OVM_TYPE_F32) + LOAD_CASE(0x2B, OVM_TYPE_F64) - case 0x2A: { - int alignment = uleb128_to_uint(ctx->binary.data, &ctx->offset); - int offset = uleb128_to_uint(ctx->binary.data, &ctx->offset); - ovm_code_builder_add_load(&ctx->builder, OVM_TYPE_F32, offset); - break; - } + LOAD_CASE(0x2C, OVM_TYPE_I8) + LOAD_CASE(0x2D, OVM_TYPE_I8) + LOAD_CASE(0x2E, OVM_TYPE_I16) + LOAD_CASE(0x2F, OVM_TYPE_I16) + LOAD_CASE(0x30, OVM_TYPE_I8) + LOAD_CASE(0x31, OVM_TYPE_I8) + LOAD_CASE(0x32, OVM_TYPE_I16) + LOAD_CASE(0x33, OVM_TYPE_I16) + LOAD_CASE(0x34, OVM_TYPE_I32) + LOAD_CASE(0x35, OVM_TYPE_I32) - case 0x2B: { - int alignment = uleb128_to_uint(ctx->binary.data, &ctx->offset); - int offset = uleb128_to_uint(ctx->binary.data, &ctx->offset); - ovm_code_builder_add_load(&ctx->builder, OVM_TYPE_F64, offset); - break; +#undef LOAD_CASE + +#define STORE_CASE(num, type) \ + case num : { \ + int alignment = uleb128_to_uint(ctx->binary.data, &ctx->offset); \ + int offset = uleb128_to_uint(ctx->binary.data, &ctx->offset); \ + ovm_code_builder_add_store(&ctx->builder, type, offset); \ + break; \ } - // ... More loading and storing instruction here ... + STORE_CASE(0x36, OVM_TYPE_I32); + STORE_CASE(0x37, OVM_TYPE_I64); + STORE_CASE(0x38, OVM_TYPE_F32); + STORE_CASE(0x39, OVM_TYPE_F64); - case 0x36: { - int alignment = uleb128_to_uint(ctx->binary.data, &ctx->offset); - int offset = uleb128_to_uint(ctx->binary.data, &ctx->offset); - ovm_code_builder_add_store(&ctx->builder, OVM_TYPE_I32, offset); - break; - } + STORE_CASE(0x3A, OVM_TYPE_I8); + STORE_CASE(0x3B, OVM_TYPE_I16); + STORE_CASE(0x3C, OVM_TYPE_I8); + STORE_CASE(0x3D, OVM_TYPE_I16); + STORE_CASE(0x3E, OVM_TYPE_I32); - case 0x37: { - int alignment = uleb128_to_uint(ctx->binary.data, &ctx->offset); - int offset = uleb128_to_uint(ctx->binary.data, &ctx->offset); - ovm_code_builder_add_store(&ctx->builder, OVM_TYPE_I64, offset); - break; - } +#undef STORE_CASE - case 0x38: { - int alignment = uleb128_to_uint(ctx->binary.data, &ctx->offset); - int offset = uleb128_to_uint(ctx->binary.data, &ctx->offset); - ovm_code_builder_add_store(&ctx->builder, OVM_TYPE_F32, offset); - break; + case 0x3F: { + assert(CONSUME_BYTE(ctx) == 0x00); + + int memory_size = 65536; + ovm_code_builder_add_imm(&ctx->builder, OVM_TYPE_I32, &memory_size); } - case 0x39: { - int alignment = uleb128_to_uint(ctx->binary.data, &ctx->offset); - int offset = uleb128_to_uint(ctx->binary.data, &ctx->offset); - ovm_code_builder_add_store(&ctx->builder, OVM_TYPE_F64, offset); + case 0x40: { + assert(CONSUME_BYTE(ctx) == 0x00); break; } @@ -606,6 +651,13 @@ static void parse_instruction(build_context *ctx) { break; } + case 0x45: { + int zero = 0; + ovm_code_builder_add_imm(&ctx->builder, OVM_TYPE_I32, &zero); + ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_EQ, OVM_TYPE_I32)); + break; + } + case 0x46: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_EQ, OVM_TYPE_I32)); break; case 0x47: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_NE, OVM_TYPE_I32)); break; case 0x48: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_LT_S, OVM_TYPE_I32)); break; @@ -617,6 +669,12 @@ static void parse_instruction(build_context *ctx) { case 0x4E: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_GE_S, OVM_TYPE_I32)); break; case 0x4F: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_GE, OVM_TYPE_I32)); break; + case 0x50: { + long long zero = 0; + ovm_code_builder_add_imm(&ctx->builder, OVM_TYPE_I64, &zero); + ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_EQ, OVM_TYPE_I64)); + break; + } case 0x51: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_EQ, OVM_TYPE_I64)); break; case 0x52: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_NE, OVM_TYPE_I64)); break; case 0x53: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_LT_S, OVM_TYPE_I64)); break; @@ -741,6 +799,8 @@ static void parse_instruction(build_context *ctx) { case 0xC3: ovm_code_builder_add_unop (&ctx->builder, OVM_TYPED_INSTR(OVMI_CVT_I16_S, OVM_TYPE_I64)); break; case 0xC4: ovm_code_builder_add_unop (&ctx->builder, OVM_TYPED_INSTR(OVMI_CVT_I32_S, OVM_TYPE_I64)); break; + case 0xFC: parse_fc_instruction(ctx); break; + default: assert(("UNHANDLED INSTRUCTION", 0)); } } @@ -780,7 +840,7 @@ static void parse_code_section(build_context *ctx) { ovm_code_builder_add_return(&ctx->builder); char *func_name = bh_aprintf(bh_heap_allocator(), "wasm_loaded_%d", bh_arr_length(ctx->program->funcs)); - ovm_program_register_func(ctx->program, func_name, ctx->builder.start_instr, ctx->builder.param_count, ctx->builder.highest_value_number); + ovm_program_register_func(ctx->program, func_name, ctx->builder.start_instr, ctx->builder.param_count, ctx->builder.highest_value_number + 1); ovm_code_builder_free(&ctx->builder); } } diff --git a/src/wasm_cli_test.c b/src/wasm_cli_test.c index 1fe6020..f0d8414 100644 --- a/src/wasm_cli_test.c +++ b/src/wasm_cli_test.c @@ -46,6 +46,6 @@ int main(int argc, char *argv[]) { bh_printf("exports: %b %d\n", export_name->data, export_name->size, wasm_externtype_kind(wasm_exporttype_type(exports.data[i]))); } - ovm_program_print_instructions(module->program, 0, 128); + ovm_program_print_instructions(module->program, 0, 150); } diff --git a/tests/wasm/out.wasm b/tests/wasm/out.wasm index d6d11ba..a88779e 100644 Binary files a/tests/wasm/out.wasm and b/tests/wasm/out.wasm differ diff --git a/tests/wasm/real.onyx b/tests/wasm/real.onyx new file mode 100644 index 0000000..cbb4128 --- /dev/null +++ b/tests/wasm/real.onyx @@ -0,0 +1,5 @@ +#load "core/std" + +main :: () { + core.println("Hello, World!"); +} \ No newline at end of file diff --git a/tests/wasm/tiny.onyx b/tests/wasm/tiny.onyx index c38b6b1..b16a114 100644 --- a/tests/wasm/tiny.onyx +++ b/tests/wasm/tiny.onyx @@ -16,10 +16,11 @@ g :: (x) => x + 1; foo(); if_test(10); + while_test(10); } if_test :: (x: i32) { - if x > 10 { + if !(x > 10) { f(10, 20); } elseif x > 5 { foo(); @@ -28,4 +29,10 @@ if_test :: (x: i32) { } } +while_test :: (x: i32) { + while i := 0; i < x { + i += 1; + } +} + foo :: () -> void #foreign "test" "asdfasdf" ---