From: Brendan Hansen Date: Sun, 26 Jun 2022 22:03:50 +0000 (-0500) Subject: successfully compiling 'real.onyx' to ovm! X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=e80bac5a4d48c268ff4a15da5bf0bf4df553eeff;p=onyx-embedder.git successfully compiling 'real.onyx' to ovm! --- diff --git a/build.sh b/build.sh index 42da70a..160e456 100755 --- a/build.sh +++ b/build.sh @@ -3,7 +3,7 @@ CC="gcc" WARNINGS='-Wimplicit -Wmisleading-indentation -Wparentheses -Wsequence-point -Wreturn-type -Wshift-negative-value -Wunused-but-set-parameter -Wunused-but-set-variable -Wunused-function -Wunused-label -Wmaybe-uninitialized -Wsign-compare -Wstrict-overflow -Wduplicated-branches -Wduplicated-cond -Wtrigraphs -Waddress -Wlogical-op' FLAGS="-g3" -LIBS= +LIBS="-pthread" INCLUDES="-I include" TARGET="libonyx_embedder.so" C_FILES="src/wasm.c src/vm/*.c src/wasm/*.c" @@ -13,7 +13,7 @@ $CC $FLAGS $INCLUDES -shared -fPIC -o $TARGET $C_FILES $LIBS $WARNINGS C_FILES="src/ovm_cli_test.c" TARGET=bin/ovm_cli_test -LIBS="-L$(pwd) -lonyx_embedder -lm -Wl,-rpath=./" +LIBS="-L$(pwd) -lonyx_embedder -pthread -lm -Wl,-rpath=./" $CC $FLAGS $INCLUDES -o $TARGET $C_FILES $LIBS $WARNINGS diff --git a/include/vm.h b/include/vm.h index 2b5157b..080ae04 100644 --- a/include/vm.h +++ b/include/vm.h @@ -3,6 +3,7 @@ #include "bh.h" #include +#include typedef u8 ovm_valtype_t; typedef i32 ovm_valnum_t; @@ -73,6 +74,7 @@ int ovm_program_register_static_ints(ovm_program_t *program, int len, int *data void ovm_program_register_func(ovm_program_t *program, char *name, i32 instr, i32 param_count, i32 value_number_count); void ovm_program_register_external_func(ovm_program_t *program, char *name, i32 param_count, i32 external_func_idx); void ovm_program_begin_func(ovm_program_t *program, char *name, i32 param_count, i32 value_number_count); +void ovm_program_modify_static_int(ovm_program_t *program, int arr, int idx, int new_value); // // Represents the running configuration and static @@ -82,6 +84,8 @@ void ovm_program_begin_func(ovm_program_t *program, char *name, i32 param_count, struct ovm_engine_t { ovm_store_t *store; + pthread_mutex_t atomic_mutex; + i64 memory_size; // This is probably going to always be 4GiB. void *memory; }; @@ -234,6 +238,7 @@ struct ovm_instr_t { #define OVM_INSTR_TYPE(instr) ((instr).full_instr >> 24) #define OVM_INSTR_INSTR(instr) ((instr).full_instr & 0xffffff) +#define OVMI_ATOMIC 0x00800000 // Flag an instruction as atomic #define OVMI_NOP 0x00 #define OVMI_ADD 0x01 // %r = %a + %b @@ -322,6 +327,8 @@ struct ovm_instr_t { #define OVMI_TRANSMUTE_F32 0x6C // %r = *(t *) &%a (reinterpret bytes) #define OVMI_TRANSMUTE_F64 0x6D // %r = *(t *) &%a (reinterpret bytes) +#define OVMI_CMPXCHG 0x70 // %r = %r == %a ? %b : %r + // // OVM_TYPED_INSTR(OVMI_ADD, OVM_TYPE_I32) == instruction for adding i32s // diff --git a/include/vm_codebuilder.h b/include/vm_codebuilder.h index cd078d0..c3c2d7e 100644 --- a/include/vm_codebuilder.h +++ b/include/vm_codebuilder.h @@ -40,9 +40,17 @@ struct label_target_t { i32 instr; }; +enum branch_patch_kind_t { + branch_patch_instr_a, // For patching the '.a' register of a branch instruction. + branch_patch_static_idx, // For patching an integer in the static integers section. +}; + struct branch_patch_t { + enum branch_patch_kind_t kind; i32 branch_instr; i32 label_idx; + i32 static_arr; + i32 static_idx; }; ovm_code_builder_t ovm_code_builder_new(ovm_program_t *program, i32 param_count, i32 local_count); @@ -52,6 +60,7 @@ void ovm_code_builder_add_unop(ovm_code_builder_t *builder, u32 in void ovm_code_builder_add_imm(ovm_code_builder_t *builder, u32 ovm_type, void *imm); void ovm_code_builder_add_branch(ovm_code_builder_t *builder, i32 label_idx); void ovm_code_builder_add_cond_branch(ovm_code_builder_t *builder, i32 label_idx); +void ovm_code_builder_add_branch_table(ovm_code_builder_t *builder, i32 count, i32 *label_indicies, i32 default_label_idx); void ovm_code_builder_add_return(ovm_code_builder_t *builder); void ovm_code_builder_add_call(ovm_code_builder_t *builder, i32 func_idx, i32 param_count, bool has_return_value); void ovm_code_builder_add_indirect_call(ovm_code_builder_t *builder, i32 param_count, bool has_return_value); @@ -62,6 +71,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_cmpxchg(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); diff --git a/src/tools/assembler.c b/src/tools/assembler.c index 2610ffe..147a5fe 100644 --- a/src/tools/assembler.c +++ b/src/tools/assembler.c @@ -191,6 +191,8 @@ static struct instruction_mapping_t instr_map[] = { { "cvt.f64.i32", OVM_TYPED_INSTR(OVMI_CVT_F64, OVM_TYPE_I32), op_reg, op_reg }, { "cvt.f64.i64", OVM_TYPED_INSTR(OVMI_CVT_F64, OVM_TYPE_I64), op_reg, op_reg }, { "cvt.f64.f32", OVM_TYPED_INSTR(OVMI_CVT_F64, OVM_TYPE_F32), op_reg, op_reg }, + + { "atomic.add.i32", OVM_TYPED_INSTR(OVMI_ADD | OVMI_ATOMIC, OVM_TYPE_I32), op_reg, op_reg, op_reg }, }; void parse_register(i32 *dest) { diff --git a/src/vm/code_builder.c b/src/vm/code_builder.c index 3701078..b6b1be7 100644 --- a/src/vm/code_builder.c +++ b/src/vm/code_builder.c @@ -93,6 +93,7 @@ void ovm_code_builder_add_branch(ovm_code_builder_t *builder, i32 label_idx) { branch_instr.a = -1; branch_patch_t patch; + patch.kind = branch_patch_instr_a; patch.branch_instr = bh_arr_length(builder->program->code); patch.label_idx = label_idx; @@ -108,6 +109,7 @@ void ovm_code_builder_add_cond_branch(ovm_code_builder_t *builder, i32 label_idx branch_instr.b = POP_VALUE(builder); branch_patch_t patch; + patch.kind = branch_patch_instr_a; patch.branch_instr = bh_arr_length(builder->program->code); patch.label_idx = label_idx; @@ -116,6 +118,61 @@ void ovm_code_builder_add_cond_branch(ovm_code_builder_t *builder, i32 label_idx ovm_program_add_instructions(builder->program, 1, &branch_instr); } +void ovm_code_builder_add_branch_table(ovm_code_builder_t *builder, i32 count, i32 *label_indicies, i32 default_label_idx) { + // + // Passing label indicies here is a little disingenuous, because that is not + // what the data will have to be. But since it is already the correct length + // I am using it as a subsitute. + int table_idx = ovm_program_register_static_ints(builder->program, count, label_indicies); + assert(table_idx > 0); + + ovm_instr_t instrs[5] = {0}; + int tmp_register = NEXT_VALUE(builder); + int index_register = POP_VALUE(builder); + PUSH_VALUE(builder, tmp_register); + + instrs[0].full_instr = OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_I32); + instrs[0].r = tmp_register; + instrs[0].i = count; + + instrs[1].full_instr = OVM_TYPED_INSTR(OVMI_LE, OVM_TYPE_I32); + instrs[1].r = tmp_register; + instrs[1].a = index_register; + instrs[1].b = tmp_register; + + instrs[2].full_instr = OVMI_BR_Z; + instrs[2].a = -1; + instrs[2].b = tmp_register; + + instrs[3].full_instr = OVMI_IDX_ARR; + instrs[3].r = tmp_register; + instrs[3].a = table_idx; + instrs[3].b = index_register; + + instrs[4].full_instr = OVMI_BRI; + instrs[4].a = tmp_register; + + POP_VALUE(builder); + + fori (i, 0, count) { + branch_patch_t patch; + patch.kind = branch_patch_static_idx; + patch.branch_instr = bh_arr_length(builder->program->code) + 4; + patch.label_idx = label_indicies[i]; + patch.static_arr = table_idx; + patch.static_idx = i; + bh_arr_push(builder->branch_patches, patch); + } + + branch_patch_t default_patch; + default_patch.kind = branch_patch_instr_a; + default_patch.branch_instr = bh_arr_length(builder->program->code) + 2; + default_patch.label_idx = default_label_idx; + bh_arr_push(builder->branch_patches, default_patch); + + ovm_program_add_instructions(builder->program, 5, instrs); +} + void ovm_code_builder_add_return(ovm_code_builder_t *builder) { ovm_instr_t instr = {0}; instr.full_instr = OVMI_RETURN; @@ -304,6 +361,47 @@ 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_cmpxchg(ovm_code_builder_t *builder, u32 ovm_type, i32 offset) { + if (offset == 0) { + ovm_instr_t cmpxchg_instr = {0}; + cmpxchg_instr.full_instr = OVM_TYPED_INSTR(OVMI_ATOMIC | OVMI_CMPXCHG, ovm_type); + cmpxchg_instr.b = POP_VALUE(builder); + cmpxchg_instr.a = POP_VALUE(builder); + cmpxchg_instr.r = POP_VALUE(builder); + + ovm_program_add_instructions(builder->program, 1, &cmpxchg_instr); + + PUSH_VALUE(builder, cmpxchg_instr.r); + return; + } + + ovm_instr_t instrs[3] = {0}; + int value_reg = POP_VALUE(builder); + int expected_reg = POP_VALUE(builder); + int addr_reg = POP_VALUE(builder); + + // imm.i32 %n, offset + instrs[0].full_instr = OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_I32); + instrs[0].i = offset; + instrs[0].r = NEXT_VALUE(builder); + + // add.i32 %n, %n, %i + instrs[1].full_instr = OVM_TYPED_INSTR(OVMI_ADD, OVM_TYPE_I32); + instrs[1].r = instrs[0].r; + instrs[1].a = instrs[0].r; + instrs[1].b = addr_reg; + + // cmpxchg.x %m, %n + instrs[2].full_instr = OVM_TYPED_INSTR(OVMI_ATOMIC | OVMI_CMPXCHG, ovm_type); + instrs[2].r = instrs[1].r; + instrs[2].a = expected_reg; + instrs[2].b = value_reg; + + ovm_program_add_instructions(builder->program, 3, instrs); + + PUSH_VALUE(builder, instrs[2].r); +} + void ovm_code_builder_add_memory_copy(ovm_code_builder_t *builder) { ovm_instr_t instr = {0}; instr.full_instr = OVMI_COPY; diff --git a/src/vm/vm.c b/src/vm/vm.c index 3ef3af1..7084ac3 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -3,6 +3,7 @@ #include #include #include // REMOVE THIS!!! only needed for sqrt +#include // // Store @@ -57,6 +58,15 @@ int ovm_program_register_static_ints(ovm_program_t *program, int len, int *data) return bh_arr_length(program->static_data) - 1; } +void ovm_program_modify_static_int(ovm_program_t *program, int arr, int idx, int new_value) { + if (arr >= bh_arr_length(program->static_data)) return; + + ovm_static_integer_array_t array = program->static_data[arr]; + if (idx >= array.len) return; + + program->static_integers[array.start_idx + idx] = new_value; +} + void ovm_program_register_func(ovm_program_t *program, char *name, i32 instr, i32 param_count, i32 value_number_count) { ovm_func_t func; func.kind = OVM_FUNC_INTERNAL; @@ -99,7 +109,9 @@ void ovm_program_add_instructions(ovm_program_t *program, i32 instr_count, ovm_i static char *ovm_instr_name(i32 full_instr) { -#define C(...) case __VA_ARGS__: return #__VA_ARGS__; +#define C(...) \ + case __VA_ARGS__: return #__VA_ARGS__; \ + case __VA_ARGS__ | OVMI_ATOMIC: return "ATOMIC_" #__VA_ARGS__; static char buf[64]; @@ -350,6 +362,11 @@ static char *ovm_instr_name(i32 full_instr) { C(OVM_TYPED_INSTR(OVMI_CVT_F64, OVM_TYPE_I64)) C(OVM_TYPED_INSTR(OVMI_CVT_F64, OVM_TYPE_F32)) + C(OVM_TYPED_INSTR(OVMI_CMPXCHG, OVM_TYPE_I8)) + C(OVM_TYPED_INSTR(OVMI_CMPXCHG, OVM_TYPE_I16)) + C(OVM_TYPED_INSTR(OVMI_CMPXCHG, OVM_TYPE_I32)) + C(OVM_TYPED_INSTR(OVMI_CMPXCHG, OVM_TYPE_I64)) + default: snprintf(buf, 64, "unknown (%d)", full_instr); return buf; @@ -547,6 +564,7 @@ void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *progr #define VAL(loc) (state->numbered_values[(u32) (loc + state->value_number_offset)]) ovm_instr_t *code = program->code; + bool release_mutex_at_end = false; while (state->pc < bh_arr_length(program->code)) { // @@ -557,6 +575,13 @@ void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *progr // being executed. - brendanfh 2022/06/13 ovm_instr_t instr = code[state->pc++]; + if (instr.full_instr & OVMI_ATOMIC) { + pthread_mutex_lock(&engine->atomic_mutex); + release_mutex_at_end = true; + + instr.full_instr &= ~OVMI_ATOMIC; + } + switch (instr.full_instr) { case OVMI_NOP: break; @@ -978,6 +1003,21 @@ void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *progr #undef CVT + +#define CMPXCHG(otype, ctype) \ + case OVM_TYPED_INSTR(OVMI_ATOMIC | OVMI_CMPXCHG, otype): \ + if (VAL(instr.r).ctype == VAL(instr.a).ctype) { \ + VAL(instr.r).ctype = VAL(instr.b).ctype ; \ + } \ + break; + + CMPXCHG(OVM_TYPE_I8, i8) + CMPXCHG(OVM_TYPE_I16, i16) + CMPXCHG(OVM_TYPE_I32, i32) + CMPXCHG(OVM_TYPE_I64, i64) + +#undef CMPXCHG + default: printf("ERROR:\n"); ovm_program_print_instructions(program, state->pc - 1, 1); @@ -985,6 +1025,11 @@ void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *progr assert(("ILLEGAL INSTRUCTION", 0)); break; } + + if (release_mutex_at_end) { + pthread_mutex_unlock(&engine->atomic_mutex); + release_mutex_at_end = false; + } } } diff --git a/src/wasm/module_parsing.c.incl b/src/wasm/module_parsing.c.incl index 2ee8941..1b4e7dd 100644 --- a/src/wasm/module_parsing.c.incl +++ b/src/wasm/module_parsing.c.incl @@ -18,6 +18,8 @@ struct build_context { ovm_program_t *program; ovm_store_t *store; + int func_table_arr_idx; + // This will be set/reset for every code (function) entry. ovm_code_builder_t builder; }; @@ -301,6 +303,8 @@ static void parse_elem_section(build_context *ctx) { fori (i, 0, (int) entry_count) { ctx->module->elem_entries[i] = uleb128_to_uint(ctx->binary.data, &ctx->offset); } + + ctx->func_table_arr_idx = ovm_program_register_static_ints(ctx->program, entry_count, ctx->module->elem_entries); } static void parse_data_section(build_context *ctx) { @@ -377,7 +381,18 @@ static void pop_label_target(build_context *ctx) { branch_patch_t patch = ctx->builder.branch_patches[i]; if (patch.label_idx != target.idx) continue; - ctx->program->code[patch.branch_instr].a = target.instr - patch.branch_instr - 1; + int br_delta = target.instr - patch.branch_instr - 1; + + switch (patch.kind) { + case branch_patch_instr_a: + ctx->program->code[patch.branch_instr].a = br_delta; + break; + + case branch_patch_static_idx: + ovm_program_modify_static_int(ctx->program, patch.static_arr, patch.static_idx, br_delta); + break; + } + bh_arr_fastdelete(ctx->builder.branch_patches, i); i--; } @@ -429,6 +444,69 @@ static void parse_fc_instruction(build_context *ctx) { } } +static void parse_fe_instruction(build_context *ctx) { + int instr_num = uleb128_to_uint(ctx->binary.data, &ctx->offset); + + switch (instr_num) { + +#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, OVMI_ATOMIC | type, offset); \ + break; \ + } + + LOAD_CASE(0x10, OVM_TYPE_I32) + LOAD_CASE(0x11, OVM_TYPE_I64) + LOAD_CASE(0x12, OVM_TYPE_I8) + LOAD_CASE(0x13, OVM_TYPE_I16) + LOAD_CASE(0x14, OVM_TYPE_I8) + LOAD_CASE(0x15, OVM_TYPE_I16) + LOAD_CASE(0x16, OVM_TYPE_I32) + +#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, OVMI_ATOMIC | type, offset); \ + break; \ + } + + STORE_CASE(0x17, OVM_TYPE_I32) + STORE_CASE(0x18, OVM_TYPE_I64) + STORE_CASE(0x19, OVM_TYPE_I8) + STORE_CASE(0x1A, OVM_TYPE_I16) + STORE_CASE(0x1B, OVM_TYPE_I8) + STORE_CASE(0x1C, OVM_TYPE_I16) + STORE_CASE(0x1D, OVM_TYPE_I32) + +#undef STORE_CASE + +#define CMPXCHG_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_cmpxchg(&ctx->builder, type, offset); \ + break; \ + } + + CMPXCHG_CASE(0x48, OVM_TYPE_I32) + CMPXCHG_CASE(0x49, OVM_TYPE_I64) + CMPXCHG_CASE(0x4A, OVM_TYPE_I8) + CMPXCHG_CASE(0x4B, OVM_TYPE_I16) + CMPXCHG_CASE(0x4C, OVM_TYPE_I8) + CMPXCHG_CASE(0x4D, OVM_TYPE_I16) + CMPXCHG_CASE(0x4E, OVM_TYPE_I32) + +#undef CMPXCHG_CASE + + default: assert(("UNHANDLED ATOMIC INSTRUCTION... SORRY :/", 0)); + } +} + static void parse_instruction(build_context *ctx) { unsigned char instr_byte = CONSUME_BYTE(ctx); switch (instr_byte) { @@ -470,7 +548,7 @@ static void parse_instruction(build_context *ctx) { // Therefore, this "peeks" at what the next label index will be, so it can // know what label to track for where to jump. It feels like there should be // a better way to do this. - ovm_code_builder_add_branch(&ctx->builder, ctx->builder.next_label_idx); + ovm_code_builder_add_branch(&ctx->builder, bh_arr_last(ctx->builder.label_stack).idx); pop_label_target(ctx); push_label_target(ctx, label_kind_block); break; @@ -497,8 +575,18 @@ static void parse_instruction(build_context *ctx) { break; } - case 0x0E: assert(0); { - // TODO: Branch tables + case 0x0E: { + // Branch tables are the most complicated thing ever :/ + + int entry_count = uleb128_to_uint(ctx->binary.data, &ctx->offset); + int *entries = bh_alloc_array(bh_heap_allocator(), int, entry_count); + fori (i, 0, entry_count) { + entries[i] = uleb128_to_uint(ctx->binary.data, &ctx->offset); + } + + int default_entry = uleb128_to_uint(ctx->binary.data, &ctx->offset); + + ovm_code_builder_add_branch_table(&ctx->builder, entry_count, entries, default_entry); break; } @@ -618,6 +706,7 @@ static void parse_instruction(build_context *ctx) { int memory_size = 65536; ovm_code_builder_add_imm(&ctx->builder, OVM_TYPE_I32, &memory_size); + break; } case 0x40: { @@ -646,7 +735,7 @@ static void parse_instruction(build_context *ctx) { case 0x44: { double value = * (f64 *) &ctx->binary.data[ctx->offset]; - ctx->offset += 4; + ctx->offset += 8; ovm_code_builder_add_imm(&ctx->builder, OVM_TYPE_F64, &value); break; } @@ -800,6 +889,7 @@ static void parse_instruction(build_context *ctx) { 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; + case 0xFE: parse_fe_instruction(ctx); break; default: assert(("UNHANDLED INSTRUCTION", 0)); } @@ -830,10 +920,10 @@ static void parse_code_section(build_context *ctx) { // Set up a lot of stuff... - i32 param_count = wasm_module_index_functype(ctx->module, i)->type.func.params.size; + i32 param_count = ctx->module->functypes.data[i]->type.func.params.size; ctx->builder = ovm_code_builder_new(ctx->program, param_count, total_locals); - ctx->builder.func_table_arr_idx = 0; // This might not be right + ctx->builder.func_table_arr_idx = ctx->func_table_arr_idx; push_label_target(ctx, label_kind_func); parse_expression(ctx); diff --git a/src/wasm_cli_test.c b/src/wasm_cli_test.c index f0d8414..5f06ea9 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, 150); + ovm_program_print_instructions(module->program, 0, bh_arr_length(module->program->code)); } diff --git a/tests/ovm/out.ovm b/tests/ovm/out.ovm index 208d51a..19fd7f2 100644 Binary files a/tests/ovm/out.ovm and b/tests/ovm/out.ovm differ diff --git a/tests/ovm/test.asm b/tests/ovm/test.asm index f6d8ffb..0571ebf 100644 --- a/tests/ovm/test.asm +++ b/tests/ovm/test.asm @@ -48,6 +48,7 @@ calli %4 reg.set stack_ptr, %10 + atomic.add.i32 %0, %0, %0 return .func sin_test 0 diff --git a/tests/wasm/out.wasm b/tests/wasm/out.wasm index a88779e..349576f 100644 Binary files a/tests/wasm/out.wasm and b/tests/wasm/out.wasm differ diff --git a/tests/wasm/tiny.onyx b/tests/wasm/tiny.onyx index b16a114..7762ca7 100644 --- a/tests/wasm/tiny.onyx +++ b/tests/wasm/tiny.onyx @@ -15,11 +15,11 @@ g :: (x) => x + 1; foo(); - if_test(10); + switch_test(10); while_test(10); } -if_test :: (x: i32) { +/*if_test :: (x: i32) { if !(x > 10) { f(10, 20); } elseif x > 5 { @@ -27,6 +27,22 @@ if_test :: (x: i32) { } else { y := x * 2; } +}*/ + +switch_test :: (x: i32) { + switch x { + case 10 { + y := 0; + } + + case 20 { + z := x * 2; + } + + case #default { + w := x + 2; + } + } } while_test :: (x: i32) {