From: Brendan Hansen Date: Thu, 16 Jun 2022 03:34:18 +0000 (-0500) Subject: more complete and nicer assembler X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=ebc8c69e24f324056c70fc69518572eff5cc1e42;p=onyx-embedder.git more complete and nicer assembler --- diff --git a/build.sh b/build.sh index b4bc9a7..cea3591 100755 --- a/build.sh +++ b/build.sh @@ -12,7 +12,7 @@ $CC $FLAGS $INCLUDES -shared -fPIC -o $TARGET $C_FILES $LIBS $WARNINGS C_FILES="src/cli.c" TARGET=onyx-debug -LIBS="-L$(pwd) -lonyx_embedder -Wl,-rpath=./" +LIBS="-L$(pwd) -lonyx_embedder -lm -Wl,-rpath=./" $CC $FLAGS $INCLUDES -o $TARGET $C_FILES $LIBS $WARNINGS diff --git a/docs/fileformat.md b/docs/fileformat.md index 96b3947..362fbc1 100644 --- a/docs/fileformat.md +++ b/docs/fileformat.md @@ -38,3 +38,9 @@ The names in numerical order. func-count | (param-count | name-len-with-null (32-bit integer) | name data (null-terminated)) ... +### Register Info +Register count +Register names + +register-count | (name-len-with-null (32-bit integer) | name data (null-terminated)) ... + diff --git a/include/assembler.h b/include/assembler.h index 2205e94..7ea656e 100644 --- a/include/assembler.h +++ b/include/assembler.h @@ -7,7 +7,12 @@ typedef struct token_t token_t; enum token_type_t { token_none, token_newline, + token_integer, + token_integer_long, + token_float, + token_float_double, + token_command, token_symbol, token_register, diff --git a/include/vm.h b/include/vm.h index 0a66d8e..6018f6f 100644 --- a/include/vm.h +++ b/include/vm.h @@ -43,12 +43,12 @@ struct ovm_static_data_t { // VM. It can be constructed incrementally as needed. // struct ovm_program_t { - ovm_store_t *store; - + bh_arr(ovm_instr_t) code; bh_arr(ovm_func_t) funcs; bh_arr(ovm_native_func_t) native_funcs; - bh_arr(ovm_instr_t) code; + i32 register_count; + ovm_store_t *store; }; ovm_program_t *ovm_program_new(ovm_store_t *store); @@ -94,9 +94,10 @@ struct ovm_state_t { bh_arr(ovm_value_t) numbered_values; bh_arr(ovm_value_t) params; bh_arr(ovm_stack_frame_t) stack_frames; + bh_arr(ovm_value_t) registers; }; -ovm_state_t *ovm_state_new(ovm_engine_t *engine); +ovm_state_t *ovm_state_new(ovm_engine_t *engine, ovm_program_t *program); void ovm_state_delete(ovm_state_t *state); @@ -126,8 +127,6 @@ struct ovm_func_t { i32 param_count; i32 value_number_count; - - // return type }; ovm_func_t *ovm_func_new(); @@ -203,54 +202,69 @@ struct ovm_instr_t { #define OVMI_NOP 0x00 -#define OVMI_ADD 0x01 // $r = $a + $b -#define OVMI_SUB 0x02 // $r = $a - $b -#define OVMI_MUL 0x03 // $r = $a * $b -#define OVMI_DIV 0x04 // $r = $a / $b -#define OVMI_REM 0x05 // $r = $a % $b - -#define OVMI_AND 0x06 // $r = $a & $b -#define OVMI_OR 0x07 // $r = $a | $b -#define OVMI_XOR 0x08 // $r = $a ^ $b -#define OVMI_NOT 0x09 // $r = ~$a -#define OVMI_SHL 0x0A // $r = $a << $b -#define OVMI_SHR 0x0B // $r = $a >> $b -#define OVMI_SAR 0x0C // $r = $a >>> $b - -#define OVMI_IMM 0x10 // $r = i/l/f/d -#define OVMI_MOV 0x10 // $r = $a -#define OVMI_LOAD 0x11 // $r = mem[$a] -#define OVMI_STORE 0x12 // mem[$a] = $b -#define OVMI_COPY 0x13 // memcpy($r, $a, $b) -#define OVMI_FILL 0x14 // memset($r, $a, $b) - -#define OVMI_LT 0x20 // $r = $a < $b -#define OVMI_LT_S 0x21 // $r = $a < $b -#define OVMI_LE 0x22 // $r = $a <= $b -#define OVMI_LE_S 0x23 // $r = $a <= $b -#define OVMI_EQ 0x24 // $r = $a == $b -#define OVMI_GE 0x25 // $r = $a >= $b -#define OVMI_GE_S 0x26 // $r = $a >= $b -#define OVMI_GT 0x27 // $r = $a > $b -#define OVMI_GT_S 0x28 // $r = $a > $b -#define OVMI_NE 0x29 // $r = $a != $b - -#define OVMI_PARAM 0x30 // push $a -#define OVMI_RETURN 0x31 // return $a -#define OVMI_CALL 0x32 // $r = a(...) -#define OVMI_NATIVE_CALL 0x33 // $r = a(...) -#define OVMI_CALLI 0x34 // $r = $a(...) -#define OVMI_NATIVE_CALLI 0x35 // $r = $a(...) +#define OVMI_ADD 0x01 // %r = %a + %b +#define OVMI_SUB 0x02 // %r = %a - %b +#define OVMI_MUL 0x03 // %r = %a * %b +#define OVMI_DIV 0x04 // %r = %a / %b +#define OVMI_REM 0x05 // %r = %a % %b + +#define OVMI_AND 0x06 // %r = %a & %b +#define OVMI_OR 0x07 // %r = %a | %b +#define OVMI_XOR 0x08 // %r = %a ^ %b +#define OVMI_NOT 0x09 // %r = ~%a +#define OVMI_SHL 0x0A // %r = %a << %b +#define OVMI_SHR 0x0B // %r = %a >> %b +#define OVMI_SAR 0x0C // %r = %a >>> %b + +#define OVMI_IMM 0x10 // %r = i/l/f/d +#define OVMI_MOV 0x10 // %r = %a +#define OVMI_LOAD 0x11 // %r = mem[%a] +#define OVMI_STORE 0x12 // mem[%a] = %b +#define OVMI_COPY 0x13 // memcpy(%r, %a, %b) +#define OVMI_FILL 0x14 // memset(%r, %a, %b) +#define OVMI_REG_GET 0x15 // %r = #a +#define OVMI_REG_SET 0x16 // #r = %a + +#define OVMI_LT 0x20 // %r = %a < %b +#define OVMI_LT_S 0x21 // %r = %a < %b +#define OVMI_LE 0x22 // %r = %a <= %b +#define OVMI_LE_S 0x23 // %r = %a <= %b +#define OVMI_EQ 0x24 // %r = %a == %b +#define OVMI_GE 0x25 // %r = %a >= %b +#define OVMI_GE_S 0x26 // %r = %a >= %b +#define OVMI_GT 0x27 // %r = %a > %b +#define OVMI_GT_S 0x28 // %r = %a > %b +#define OVMI_NE 0x29 // %r = %a != %b + +#define OVMI_PARAM 0x30 // push %a +#define OVMI_RETURN 0x31 // return %a +#define OVMI_CALL 0x32 // %r = a(...) +#define OVMI_NATIVE_CALL 0x33 // %r = a(...) +#define OVMI_CALLI 0x34 // %r = %a(...) +#define OVMI_NATIVE_CALLI 0x35 // %r = %a(...) #define OVMI_BR 0x40 // br pc + a // Relative branching -#define OVMI_BR_NZ 0x41 // br pc + a if $b != 0 -#define OVMI_BRI 0x42 // br pc + $a // Relative branching -#define OVMI_BRI_NZ 0x43 // br pc + $a if $b != 0 - -#define OVMI_CLZ 0x50 // $r = clz($a) -#define OVMI_CTZ 0x51 // $r = ctr($a) -#define OVMI_POPCNT 0x52 // $r = popcnt($a) - +#define OVMI_BR_Z 0x41 // br pc + a if %b == 0 +#define OVMI_BR_NZ 0x42 // br pc + a if %b != 0 +#define OVMI_BRI 0x43 // br pc + %a // Relative branching +#define OVMI_BRI_Z 0x44 // br pc + %a if %b == 0 +#define OVMI_BRI_NZ 0x45 // br pc + %a if %b != 0 + +#define OVMI_CLZ 0x50 // %r = clz(%a) +#define OVMI_CTZ 0x51 // %r = ctr(%a) +#define OVMI_POPCNT 0x52 // %r = popcnt(%a) + +// For conversion operations, the "type" of the instruction is +// destination type, the type in the name is the source type. +#define OVMI_CVT_I8 0x60 // %r = (t) %a +#define OVMI_CVT_I16 0x61 // %r = (t) %a +#define OVMI_CVT_I32 0x62 // %r = (t) %a +#define OVMI_CVT_I64 0x63 // %r = (t) %a +#define OVMI_CVT_F32 0x64 // %r = (t) %a +#define OVMI_CVT_F64 0x65 // %r = (t) %a +#define OVMI_EXTEND_I8 0x66 // %r = (t) %a (sign extension for integers) +#define OVMI_EXTEND_I16 0x67 // %r = (t) %a (sign extension for integers) +#define OVMI_EXTEND_I32 0x68 // %r = (t) %a (sign extension for integers) // // OVM_TYPED_INSTR(OVMI_ADD, OVM_TYPE_I32) == instruction for adding i32s diff --git a/src/cli.c b/src/cli.c index 636f764..a6dde3f 100644 --- a/src/cli.c +++ b/src/cli.c @@ -1,93 +1,30 @@ #include "vm.h" +#include + void print_result(void *data, ovm_value_t *params, ovm_value_t *result) { - printf("Result: %d\n", params[0].i32); + switch (params[0].type) { + case OVM_TYPE_I32: printf("Result: %d\n", params[0].i32); break; + case OVM_TYPE_F32: printf("Result: %f\n", params[0].f32); break; + } } -int main(int argc, char *argv[]) { - - ovm_store_t *store = ovm_store_new(); - - ovm_program_t *prog = ovm_program_new(store); - -/* ovm_instr_t func1_instrs[] = { - // { .full_instr = OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_I32), 0, 10 }, - // { .full_instr = OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_I32), 1, 20 }, - // { .full_instr = OVM_TYPED_INSTR(OVMI_ADD, OVM_TYPE_F32), 2, 0, 1 }, - { .full_instr = OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_I32), 6, 10 }, - { .full_instr = OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_I32), 7, 1 }, - { .full_instr = OVMI_PARAM, 0, 0 }, - { .full_instr = OVMI_PARAM, 0, 1 }, - { .full_instr = OVMI_CALL, 2, 1 }, - { .full_instr = OVMI_PARAM, 0, 2 }, - { .full_instr = OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_F32), 4, 0 }, - { .full_instr = OVM_TYPED_INSTR(OVMI_SUB, OVM_TYPE_I32), 6, 6, 7 }, - { .full_instr = OVMI_BR_NZ, 0, -4, 6 }, - { .full_instr = OVMI_RETURN, 0, 4 }, - }; - - ovm_instr_t func2_instrs[] = { - { .full_instr = OVM_TYPED_INSTR(OVMI_ADD, OVM_TYPE_F32), 2, 0, 1 }, - { .full_instr = OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_I32), 3, 0x1000 }, - { .full_instr = OVM_TYPED_INSTR(OVMI_STORE, OVM_TYPE_F32), 0, 3, 2 }, - { .full_instr = OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_I32), 4, 0x2000 }, - { .full_instr = OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_I32), 5, 4 }, - { .full_instr = OVMI_COPY, 4, 3, 5 }, - - { .full_instr = OVM_TYPED_INSTR(OVMI_LOAD, OVM_TYPE_F32), 2, 4 }, - { .full_instr = OVMI_RETURN, 0, 2 }, - }; - - ovm_program_begin_func(prog, "main", 2, 8); - ovm_program_add_instructions(prog, sizeof(func1_instrs) / sizeof(*func1_instrs), func1_instrs); - ovm_program_begin_func(prog, "add", 2, 6); - ovm_program_add_instructions(prog, sizeof(func2_instrs) / sizeof(*func2_instrs), func2_instrs); - - ovm_instr_t add_instrs[] = { - { .full_instr = OVM_TYPED_INSTR(OVMI_ADD, OVM_TYPE_I32), 2, 0, 1 }, - { .full_instr = OVMI_RETURN, 2 }, - }; - - ovm_instr_t count_instrs[] = { - { .full_instr = OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_I32), 1, .i = 1 }, - { .full_instr = OVMI_PARAM, 0, 0 }, - { .full_instr = OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_NONE), 0, 0 }, - { .full_instr = OVM_TYPED_INSTR(OVMI_SUB, OVM_TYPE_I32), 0, 0, 1 }, - { .full_instr = OVMI_BR_NZ, 0, -4, 0 }, - { .full_instr = OVMI_RETURN, -1 }, - }; - - ovm_instr_t main_instrs[] = { - { .full_instr = OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_I32), 0, 1 }, - { .full_instr = OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_I32), 1, 2 }, - { .full_instr = OVMI_PARAM, 0, 0 }, - { .full_instr = OVMI_PARAM, 0, 1 }, - { .full_instr = OVMI_CALL, 2, 0 }, - { .full_instr = OVMI_PARAM, 0, 2 }, - { .full_instr = OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_NONE), 0, 0 }, - - { .full_instr = OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_I32), 3, .i = 10 }, - { .full_instr = OVMI_PARAM, 0, 3 }, - { .full_instr = OVMI_CALL, -1, 1 }, - }; - - ovm_program_begin_func(prog, "add", 2, 3); - ovm_program_add_instructions(prog, sizeof(add_instrs) / sizeof(*add_instrs), add_instrs); - ovm_program_begin_func(prog, "count", 1, 2); - ovm_program_add_instructions(prog, sizeof(count_instrs) / sizeof(*count_instrs), count_instrs); - ovm_program_begin_func(prog, "main", 0, 4); - ovm_program_add_instructions(prog, sizeof(main_instrs) / sizeof(*main_instrs), main_instrs); -*/ +void c_call_1f64(void *data, ovm_value_t *params, ovm_value_t *result) { + result->type = OVM_TYPE_F32; + result->f32 = (f32) ((f64 (*)(f64)) data)(params[0].f32); +} - ovm_program_register_native_func(prog, "dummy", print_result, NULL, 0); - ovm_program_register_native_func(prog, "print_int", print_result, NULL, 1); +int main(int argc, char *argv[]) { static ovm_native_func_t native_funcs[] = { { "dummy", 0, print_result, NULL }, - { "print_int", 1, print_result, NULL }, + { "print", 1, print_result, NULL }, + { "sin", 1, c_call_1f64, sin }, { NULL }, }; + ovm_store_t *store = ovm_store_new(); + ovm_program_t *prog = ovm_program_new(store); ovm_engine_t *engine = ovm_engine_new(store); ovm_program_load_from_file(prog, engine, "./out.ovm"); @@ -95,15 +32,15 @@ int main(int argc, char *argv[]) { ovm_program_print_instructions(prog, 0, bh_arr_length(prog->code)); - ovm_state_t *state = ovm_state_new(engine); + ovm_state_t *state = ovm_state_new(engine, prog); state->pc = 0; ovm_value_t values[] = { - { .type = OVM_TYPE_F32, .f32 = 20 }, - { .type = OVM_TYPE_F32, .f32 = 40 }, + { .type = OVM_TYPE_I32, .i32 = 20 }, + { .type = OVM_TYPE_I32, .i32 = 40 }, }; - ovm_value_t result = ovm_func_call(engine, state, prog, 2, 0, NULL); - // printf("%d %f\n", result.type, result.f32); + ovm_value_t result = ovm_func_call(engine, state, prog, 2, 0, values); + printf("%d %d\n", result.type, result.i32); ovm_state_delete(state); ovm_engine_delete(engine); diff --git a/src/tools/asm.l b/src/tools/asm.l index 8fde370..94b2dd9 100644 --- a/src/tools/asm.l +++ b/src/tools/asm.l @@ -43,11 +43,15 @@ ident [a-zA-Z][a-zA-Z.0-9_]* %% \n PUSH_TOKEN(token_newline) +\/\/.*\n continue; \.{ident} PUSH_TOKEN(token_command) +{ident}: PUSH_TOKEN(token_label) {ident} PUSH_TOKEN(token_symbol) \%[0-9]+ PUSH_TOKEN(token_register) +[0-9]+\.[0-9]+f PUSH_TOKEN(token_float) +[0-9]+\.[0-9]+ PUSH_TOKEN(token_float_double) +[0-9]+l PUSH_TOKEN(token_integer_long) [0-9]+ PUSH_TOKEN(token_integer) -:{ident} PUSH_TOKEN(token_label) "," PUSH_TOKEN(token_comma) . diff --git a/src/tools/assembler.c b/src/tools/assembler.c index 7a2d76a..7cb2af2 100644 --- a/src/tools/assembler.c +++ b/src/tools/assembler.c @@ -28,6 +28,7 @@ static bh_arr(ovm_instr_t) instrs; static bh_arr(ovm_func_t) funcs; static bh_arr(ovm_native_func_t) native_funcs; +static bh_arr(char *) register_names; // @@ -47,6 +48,7 @@ typedef struct active_label_t { static i32 maximum_value_number = 0; static bh_arr(patch_t) call_patches; static bh_arr(patch_t) label_patches; +static bh_arr(patch_t) register_patches; static bh_arr(active_label_t) active_labels; @@ -107,13 +109,33 @@ static struct instruction_mapping_t instr_map[] = { { "rem.i32", OVM_TYPED_INSTR(OVMI_REM, OVM_TYPE_I32), op_reg, op_imm }, { "rem.i64", OVM_TYPED_INSTR(OVMI_REM, OVM_TYPE_I64), op_reg, op_imm }, + + { "eq.i8", OVM_TYPED_INSTR(OVMI_EQ, OVM_TYPE_I8) , op_reg, op_reg, op_reg }, + { "eq.i16", OVM_TYPED_INSTR(OVMI_EQ, OVM_TYPE_I16), op_reg, op_reg, op_reg }, + { "eq.i32", OVM_TYPED_INSTR(OVMI_EQ, OVM_TYPE_I32), op_reg, op_reg, op_reg }, + { "eq.i64", OVM_TYPED_INSTR(OVMI_EQ, OVM_TYPE_I64), op_reg, op_reg, op_reg }, + { "eq.f32", OVM_TYPED_INSTR(OVMI_EQ, OVM_TYPE_F32), op_reg, op_reg, op_reg }, + { "eq.f64", OVM_TYPED_INSTR(OVMI_EQ, OVM_TYPE_F64), op_reg, op_reg, op_reg }, + + { "ne.i8", OVM_TYPED_INSTR(OVMI_NE, OVM_TYPE_I8) , op_reg, op_reg, op_reg }, + { "ne.i16", OVM_TYPED_INSTR(OVMI_NE, OVM_TYPE_I16), op_reg, op_reg, op_reg }, + { "ne.i32", OVM_TYPED_INSTR(OVMI_NE, OVM_TYPE_I32), op_reg, op_reg, op_reg }, + { "ne.i64", OVM_TYPED_INSTR(OVMI_NE, OVM_TYPE_I64), op_reg, op_reg, op_reg }, + { "ne.f32", OVM_TYPED_INSTR(OVMI_NE, OVM_TYPE_F32), op_reg, op_reg, op_reg }, + { "ne.f64", OVM_TYPED_INSTR(OVMI_NE, OVM_TYPE_F64), op_reg, op_reg, op_reg }, + // More operands to do... + { "reg.get", OVMI_REG_GET, op_reg, op_sym }, + { "reg.set", OVMI_REG_SET, op_sym, op_reg }, + { "param", OVMI_PARAM, op_none, op_reg }, { "br", OVMI_BR, op_none, op_sym }, { "bri", OVMI_BRI, op_none, op_reg }, { "br_nz", OVMI_BR_NZ, op_none, op_sym, op_reg }, { "bri_nz", OVMI_BRI_NZ, op_none, op_reg, op_reg }, + { "br_z", OVMI_BR_Z, op_none, op_sym, op_reg }, + { "bri_z", OVMI_BRI_Z, op_none, op_reg, op_reg }, { "return", OVMI_RETURN }, { "return.i8", OVMI_RETURN, op_none, op_reg }, @@ -147,13 +169,42 @@ static struct instruction_mapping_t instr_map[] = { { "native_call.f32", OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_F32), op_reg , op_sym }, { "native_call.f64", OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_F64), op_reg , op_sym }, - { "native_calli", OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_NONE), op_none, op_reg }, - { "native_calli.i8", OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_I8), op_reg , op_reg }, - { "native_calli.i16", OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_I16), op_reg , op_reg }, - { "native_calli.i32", OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_I32), op_reg , op_reg }, - { "native_calli.i64", OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_I64), op_reg , op_reg }, - { "native_calli.f32", OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_F32), op_reg , op_reg }, - { "native_calli.f64", OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_F64), op_reg , op_reg }, + { "native_calli", OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_NONE), op_none, op_reg }, + { "native_calli.i8", OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_I8), op_reg , op_reg }, + { "native_calli.i16", OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_I16), op_reg , op_reg }, + { "native_calli.i32", OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_I32), op_reg , op_reg }, + { "native_calli.i64", OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_I64), op_reg , op_reg }, + { "native_calli.f32", OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_F32), op_reg , op_reg }, + { "native_calli.f64", OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_F64), op_reg , op_reg }, + + + { "cvt.i8.i16", OVM_TYPED_INSTR(OVMI_CVT_I8, OVM_TYPE_I16), op_reg, op_reg }, + { "cvt.i8.i32", OVM_TYPED_INSTR(OVMI_CVT_I8, OVM_TYPE_I32), op_reg, op_reg }, + { "cvt.i8.i64", OVM_TYPED_INSTR(OVMI_CVT_I8, OVM_TYPE_I64), op_reg, op_reg }, + + { "cvt.i16.i8", OVM_TYPED_INSTR(OVMI_CVT_I16, OVM_TYPE_I8), op_reg, op_reg }, + { "cvt.i16.i32", OVM_TYPED_INSTR(OVMI_CVT_I16, OVM_TYPE_I32), op_reg, op_reg }, + { "cvt.i16.i64", OVM_TYPED_INSTR(OVMI_CVT_I16, OVM_TYPE_I64), op_reg, op_reg }, + + { "cvt.i32.i8", OVM_TYPED_INSTR(OVMI_CVT_I32, OVM_TYPE_I8), op_reg, op_reg }, + { "cvt.i32.i16", OVM_TYPED_INSTR(OVMI_CVT_I32, OVM_TYPE_I16), op_reg, op_reg }, + { "cvt.i32.i64", OVM_TYPED_INSTR(OVMI_CVT_I32, OVM_TYPE_I64), op_reg, op_reg }, + { "cvt.i32.f32", OVM_TYPED_INSTR(OVMI_CVT_I32, OVM_TYPE_F32), op_reg, op_reg }, + { "cvt.i32.f64", OVM_TYPED_INSTR(OVMI_CVT_I32, OVM_TYPE_F64), op_reg, op_reg }, + + { "cvt.i64.i8", OVM_TYPED_INSTR(OVMI_CVT_I64, OVM_TYPE_I8), op_reg, op_reg }, + { "cvt.i64.i16", OVM_TYPED_INSTR(OVMI_CVT_I64, OVM_TYPE_I16), op_reg, op_reg }, + { "cvt.i64.i32", OVM_TYPED_INSTR(OVMI_CVT_I64, OVM_TYPE_I32), op_reg, op_reg }, + { "cvt.i64.f32", OVM_TYPED_INSTR(OVMI_CVT_I64, OVM_TYPE_F32), op_reg, op_reg }, + { "cvt.i64.f64", OVM_TYPED_INSTR(OVMI_CVT_I64, OVM_TYPE_F64), op_reg, op_reg }, + + { "cvt.f32.i32", OVM_TYPED_INSTR(OVMI_CVT_F32, OVM_TYPE_I32), op_reg, op_reg }, + { "cvt.f32.i64", OVM_TYPED_INSTR(OVMI_CVT_F32, OVM_TYPE_I64), op_reg, op_reg }, + { "cvt.f32.f64", OVM_TYPED_INSTR(OVMI_CVT_F32, OVM_TYPE_F64), op_reg, op_reg }, + + { "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 }, }; void parse_register(i32 *dest) { @@ -168,12 +219,27 @@ void parse_register(i32 *dest) { void parse_immediate(ovm_instr_t *instr) { token_t token = asm_lexer_next_token(); - // - // Only integer immediates are supported right now. - EXPECT_TOKEN(token, token_integer); - if (OVM_INSTR_TYPE(*instr) == OVM_TYPE_I32) instr->i = atoi(token.text); - if (OVM_INSTR_TYPE(*instr) == OVM_TYPE_I64) instr->l = atol(token.text); + u32 type = OVM_INSTR_TYPE(*instr); + if (type == OVM_TYPE_I32 || type == OVM_TYPE_I16 || type == OVM_TYPE_I8) { + EXPECT_TOKEN(token, token_integer); + instr->i = atoi(token.text); + } + + if (type == OVM_TYPE_I64) { + EXPECT_TOKEN(token, token_integer_long); + instr->l = atol(token.text); + } + + if (type == OVM_TYPE_F32) { + EXPECT_TOKEN(token, token_float); + instr->f = atof(token.text); + } + + if (type == OVM_TYPE_F64) { + EXPECT_TOKEN(token, token_float_double); + instr->d = atof(token.text); + } } void parse_symbol(u32 instr_offset, ovm_instr_t *instr) { @@ -187,6 +253,7 @@ void parse_symbol(u32 instr_offset, ovm_instr_t *instr) { switch (patch.instr) { case OVMI_BR: + case OVMI_BR_Z: case OVMI_BR_NZ: bh_arr_push(label_patches, patch); break; @@ -196,6 +263,11 @@ void parse_symbol(u32 instr_offset, ovm_instr_t *instr) { bh_arr_push(call_patches, patch); break; + case OVMI_REG_SET: + case OVMI_REG_GET: + bh_arr_push(register_patches, patch); + break; + default: assert(("BAD CASE", 0)); } } @@ -241,20 +313,14 @@ void parse_instruction() { parse_symbol(bh_arr_length(instrs), &instr); \ token = asm_lexer_peek_token(); \ break; \ + } \ + if (token.type == token_comma) { \ + asm_lexer_next_token(); \ + token = asm_lexer_peek_token(); \ } PARSE_OP(r) - if (token.type == token_comma) { - asm_lexer_next_token(); - token = asm_lexer_peek_token(); - } - PARSE_OP(a) - if (token.type == token_comma) { - asm_lexer_next_token(); - token = asm_lexer_peek_token(); - } - PARSE_OP(b) bh_arr_push(instrs, instr); @@ -266,7 +332,9 @@ void parse_label() { active_label_t label; label.instr_offset = bh_arr_length(instrs); - label.name = token.text + 1; + label.name = token.text; + label.name[strlen(label.name) - 1] = '\0'; + bh_arr_push(active_labels, label); } @@ -335,6 +403,14 @@ void parse_command() { return; } + if (!strcmp(token.text, ".register")) { + token_t name_token = asm_lexer_next_token(); + EXPECT_TOKEN(name_token, token_symbol); + + bh_arr_push(register_names, name_token.text); + return; + } + UNEXPECTED_TOKEN(token); } @@ -370,7 +446,7 @@ void parse(char *input_file) { bh_file_close(&file); } -void patch_calls() { +void patch() { bh_arr_each(patch_t, patch, call_patches) { ovm_instr_t *instr = &instrs[patch->instr_offset]; @@ -396,10 +472,29 @@ void patch_calls() { instr->a = func_idx; } + bh_arr_each(patch_t, patch, register_patches) { + ovm_instr_t *instr = &instrs[patch->instr_offset]; + + i32 result_idx = -1; + i32 tmp_idx = 0; + bh_arr_each(char *, name, register_names) { + if (!strcmp(*name, patch->name)) { + result_idx = tmp_idx; + break; + } + + tmp_idx++; + } + + assert(result_idx != -1); + if (patch->instr == OVMI_REG_GET) instr->a = result_idx; + if (patch->instr == OVMI_REG_SET) instr->r = result_idx; + } } void write_file(char *output_file) { - ovm_raw_print_instructions(bh_arr_length(instrs), instrs); + // + // ovm_raw_print_instructions(bh_arr_length(instrs), instrs); bh_file file; bh_file_error error = bh_file_open_mode(&file, BH_FILE_MODE_WRITE, output_file); @@ -436,6 +531,14 @@ void write_file(char *output_file) { bh_file_write(&file, func->name, name_length); } + i32 register_count = bh_arr_length(register_names); + bh_file_write(&file, ®ister_count, 4); // Endian-dependent + bh_arr_each(char *, register_name, register_names) { + i32 name_length = strlen(*register_name) + 1; + bh_file_write(&file, &name_length, 4); + bh_file_write(&file, *register_name, name_length); + } + bh_file_close(&file); } @@ -449,7 +552,7 @@ int main(int argc, char *argv[]) { char *output_file = argv[2]; parse(input_file); - patch_calls(); + patch(); write_file(output_file); } @@ -459,7 +562,12 @@ int main(int argc, char *argv[]) { char *token_names[] = { T(token_none), T(token_newline), + T(token_integer), + T(token_integer_long), + T(token_float), + T(token_float_double), + T(token_command), T(token_symbol), T(token_register), diff --git a/src/tools/lex.yy.c b/src/tools/lex.yy.c index 8e91a3a..686217e 100644 --- a/src/tools/lex.yy.c +++ b/src/tools/lex.yy.c @@ -374,8 +374,8 @@ static void yynoreturn yy_fatal_error ( const char* msg ); (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; -#define YY_NUM_RULES 9 -#define YY_END_OF_BUFFER 10 +#define YY_NUM_RULES 13 +#define YY_END_OF_BUFFER 14 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -383,10 +383,11 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static const flex_int16_t yy_accept[20] = +static const flex_int16_t yy_accept[26] = { 0, - 0, 0, 10, 8, 1, 8, 7, 8, 5, 8, - 3, 4, 2, 5, 6, 3, 2, 6, 0 + 0, 0, 14, 12, 1, 12, 11, 12, 12, 10, + 5, 6, 3, 0, 0, 10, 9, 5, 4, 3, + 0, 2, 8, 7, 0 } ; static const YY_CHAR yy_ec[256] = @@ -395,16 +396,16 @@ static const YY_CHAR yy_ec[256] = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, - 1, 1, 1, 4, 1, 5, 1, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 7, 1, 1, - 1, 1, 1, 1, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 1, 1, 1, 1, 9, 1, 8, 8, 8, 8, - - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 4, 1, 5, 6, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 8, 1, 1, + 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 1, 1, 1, 1, 10, 1, 9, 9, 9, 9, + + 9, 11, 9, 9, 9, 9, 9, 12, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -421,43 +422,48 @@ static const YY_CHAR yy_ec[256] = 1, 1, 1, 1, 1 } ; -static const YY_CHAR yy_meta[10] = +static const YY_CHAR yy_meta[13] = { 0, - 1, 1, 1, 1, 2, 2, 1, 2, 2 + 1, 1, 1, 1, 2, 1, 2, 3, 4, 2, + 4, 4 } ; -static const flex_int16_t yy_base[23] = +static const flex_int16_t yy_base[30] = { 0, - 0, 0, 19, 20, 20, 12, 20, 9, 10, 7, - 0, 8, 0, 7, 0, 0, 0, 0, 20, 10, - 9, 8 + 0, 0, 36, 37, 37, 23, 37, 0, 18, 8, + 15, 15, 0, 17, 11, 0, 37, 9, 37, 0, + 14, 37, 14, 37, 37, 10, 24, 27, 31 } ; -static const flex_int16_t yy_def[23] = +static const flex_int16_t yy_def[30] = { 0, - 19, 1, 19, 19, 19, 19, 19, 19, 19, 19, - 20, 19, 21, 19, 22, 20, 21, 22, 0, 19, - 19, 19 + 25, 1, 25, 25, 25, 25, 25, 26, 25, 25, + 27, 25, 28, 29, 25, 10, 25, 27, 25, 28, + 29, 25, 25, 25, 0, 25, 25, 25, 25 } ; -static const flex_int16_t yy_nxt[30] = +static const flex_int16_t yy_nxt[50] = { 0, - 4, 5, 6, 7, 8, 9, 10, 11, 4, 18, - 17, 16, 14, 12, 15, 14, 13, 12, 19, 3, - 19, 19, 19, 19, 19, 19, 19, 19, 19 + 4, 5, 6, 7, 8, 9, 10, 4, 11, 4, + 11, 11, 15, 13, 16, 22, 19, 23, 22, 17, + 23, 12, 19, 14, 24, 18, 18, 18, 20, 12, + 20, 21, 21, 21, 21, 25, 3, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25 } ; -static const flex_int16_t yy_chk[30] = +static const flex_int16_t yy_chk[50] = { 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, - 21, 20, 14, 12, 10, 9, 8, 6, 3, 19, - 19, 19, 19, 19, 19, 19, 19, 19, 19 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 10, 26, 10, 21, 18, 15, 14, 10, + 23, 12, 11, 9, 23, 27, 27, 27, 28, 6, + 28, 29, 29, 29, 29, 3, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25 } ; /* Table of booleans, true if rule could match eol. */ -static const flex_int32_t yy_rule_can_match_eol[10] = +static const flex_int32_t yy_rule_can_match_eol[14] = { 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, }; +1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; static yy_state_type yy_last_accepting_state; static char *yy_last_accepting_cpos; @@ -508,8 +514,8 @@ char *yytext; #define PUSH_TOKEN(t) return ((token_t) { .type = t, .text = bh_strdup(bh_heap_allocator(), yytext), .line = yylineno }); -#line 512 "src/tools/lex.yy.c" -#line 513 "src/tools/lex.yy.c" +#line 518 "src/tools/lex.yy.c" +#line 519 "src/tools/lex.yy.c" #define INITIAL 0 @@ -729,7 +735,7 @@ YY_DECL #line 43 "src/tools/asm.l" -#line 733 "src/tools/lex.yy.c" +#line 739 "src/tools/lex.yy.c" while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { @@ -756,13 +762,13 @@ yy_match: while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 20 ) + if ( yy_current_state >= 26 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; ++yy_cp; } - while ( yy_base[yy_current_state] != 20 ); + while ( yy_base[yy_current_state] != 37 ); yy_find_action: yy_act = yy_accept[yy_current_state]; @@ -803,46 +809,67 @@ YY_RULE_SETUP PUSH_TOKEN(token_newline) YY_BREAK case 2: +/* rule 2 can match eol */ YY_RULE_SETUP #line 46 "src/tools/asm.l" -PUSH_TOKEN(token_command) +continue; YY_BREAK case 3: YY_RULE_SETUP #line 47 "src/tools/asm.l" -PUSH_TOKEN(token_symbol) +PUSH_TOKEN(token_command) YY_BREAK case 4: YY_RULE_SETUP #line 48 "src/tools/asm.l" -PUSH_TOKEN(token_register) +PUSH_TOKEN(token_label) YY_BREAK case 5: YY_RULE_SETUP #line 49 "src/tools/asm.l" -PUSH_TOKEN(token_integer) +PUSH_TOKEN(token_symbol) YY_BREAK case 6: YY_RULE_SETUP #line 50 "src/tools/asm.l" -PUSH_TOKEN(token_label) +PUSH_TOKEN(token_register) YY_BREAK case 7: YY_RULE_SETUP #line 51 "src/tools/asm.l" -PUSH_TOKEN(token_comma) +PUSH_TOKEN(token_float) YY_BREAK case 8: YY_RULE_SETUP -#line 53 "src/tools/asm.l" - +#line 52 "src/tools/asm.l" +PUSH_TOKEN(token_float_double) YY_BREAK case 9: YY_RULE_SETUP +#line 53 "src/tools/asm.l" +PUSH_TOKEN(token_integer_long) + YY_BREAK +case 10: +YY_RULE_SETUP +#line 54 "src/tools/asm.l" +PUSH_TOKEN(token_integer) + YY_BREAK +case 11: +YY_RULE_SETUP #line 55 "src/tools/asm.l" +PUSH_TOKEN(token_comma) + YY_BREAK +case 12: +YY_RULE_SETUP +#line 57 "src/tools/asm.l" + + YY_BREAK +case 13: +YY_RULE_SETUP +#line 59 "src/tools/asm.l" ECHO; YY_BREAK -#line 846 "src/tools/lex.yy.c" +#line 873 "src/tools/lex.yy.c" case YY_STATE_EOF(INITIAL): yyterminate(); @@ -1139,7 +1166,7 @@ static int yy_get_next_buffer (void) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 20 ) + if ( yy_current_state >= 26 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; @@ -1167,11 +1194,11 @@ static int yy_get_next_buffer (void) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 20 ) + if ( yy_current_state >= 26 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; - yy_is_jam = (yy_current_state == 19); + yy_is_jam = (yy_current_state == 25); return yy_is_jam ? 0 : yy_current_state; } @@ -1859,7 +1886,7 @@ void yyfree (void * ptr ) #define YYTABLES_NAME "yytables" -#line 55 "src/tools/asm.l" +#line 59 "src/tools/asm.l" token_t asm_lexer_peek_token() { diff --git a/src/vm/program_loader.c b/src/vm/program_loader.c index 78e902e..4b71042 100644 --- a/src/vm/program_loader.c +++ b/src/vm/program_loader.c @@ -81,13 +81,28 @@ bool ovm_program_load_from_file(ovm_program_t *program, ovm_engine_t *engine, ch ovm_program_register_native_func(program, name_buf, NULL, NULL, param_count); } + // + // Register section + // + bh_file_read(&file, &entry_count, sizeof(i32)); + fori (i, 0, entry_count) { + i32 param_count, name_len; + bh_file_read(&file, ¶m_count, sizeof(i32)); + bh_file_read(&file, &name_len, sizeof(i32)); + + char *name_buf = bh_alloc_array(program->store->arena_allocator, char, name_len); + bh_file_read(&file, name_buf, name_len); + + // For now, these are just ignored... + } + program->register_count = entry_count; return true; } void ovm_program_link_native_funcs(ovm_program_t *program, ovm_native_func_t *funcs) { bh_arr_each(ovm_native_func_t, nf, program->native_funcs) { - if (nf->native_func && nf->userdata) continue; + if (nf->native_func || nf->userdata) continue; ovm_native_func_t *func = funcs; while (func->name) { @@ -106,3 +121,4 @@ void ovm_program_link_native_funcs(ovm_program_t *program, ovm_native_func_t *fu } } } + diff --git a/src/vm/vm.c b/src/vm/vm.c index a004d49..82bd96c 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -26,6 +26,7 @@ void ovm_store_delete(ovm_store_t *store) { ovm_program_t *ovm_program_new(ovm_store_t *store) { ovm_program_t *program = bh_alloc_item(store->heap_allocator, ovm_program_t); program->store = store; + program->register_count = 0; bh_arr_new(store->heap_allocator, program->funcs, 16); bh_arr_new(store->heap_allocator, program->native_funcs, 16); @@ -183,6 +184,9 @@ static char *ovm_instr_name(i32 full_instr) { C(OVMI_COPY) C(OVMI_FILL) + C(OVMI_REG_GET) + C(OVMI_REG_SET) + C(OVM_TYPED_INSTR(OVMI_LT, OVM_TYPE_I8)) C(OVM_TYPED_INSTR(OVMI_LT, OVM_TYPE_I16)) C(OVM_TYPED_INSTR(OVMI_LT, OVM_TYPE_I32)) @@ -273,7 +277,39 @@ static char *ovm_instr_name(i32 full_instr) { C(OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_F64)) C(OVMI_BR) + C(OVMI_BR_Z) C(OVMI_BR_NZ) + C(OVMI_BRI) + C(OVMI_BRI_Z) + C(OVMI_BRI_NZ) + + C(OVM_TYPED_INSTR(OVMI_CVT_I8, OVM_TYPE_I16)) + C(OVM_TYPED_INSTR(OVMI_CVT_I8, OVM_TYPE_I32)) + C(OVM_TYPED_INSTR(OVMI_CVT_I8, OVM_TYPE_I64)) + + C(OVM_TYPED_INSTR(OVMI_CVT_I16, OVM_TYPE_I8)) + C(OVM_TYPED_INSTR(OVMI_CVT_I16, OVM_TYPE_I32)) + C(OVM_TYPED_INSTR(OVMI_CVT_I16, OVM_TYPE_I64)) + + C(OVM_TYPED_INSTR(OVMI_CVT_I32, OVM_TYPE_I8)) + C(OVM_TYPED_INSTR(OVMI_CVT_I32, OVM_TYPE_I16)) + C(OVM_TYPED_INSTR(OVMI_CVT_I32, OVM_TYPE_I64)) + C(OVM_TYPED_INSTR(OVMI_CVT_I32, OVM_TYPE_F32)) + C(OVM_TYPED_INSTR(OVMI_CVT_I32, OVM_TYPE_F64)) + + C(OVM_TYPED_INSTR(OVMI_CVT_I64, OVM_TYPE_I8)) + C(OVM_TYPED_INSTR(OVMI_CVT_I64, OVM_TYPE_I16)) + C(OVM_TYPED_INSTR(OVMI_CVT_I64, OVM_TYPE_I32)) + C(OVM_TYPED_INSTR(OVMI_CVT_I64, OVM_TYPE_F32)) + C(OVM_TYPED_INSTR(OVMI_CVT_I64, OVM_TYPE_F64)) + + C(OVM_TYPED_INSTR(OVMI_CVT_F32, OVM_TYPE_I32)) + C(OVM_TYPED_INSTR(OVMI_CVT_F32, OVM_TYPE_I64)) + C(OVM_TYPED_INSTR(OVMI_CVT_F32, OVM_TYPE_F64)) + + C(OVM_TYPED_INSTR(OVMI_CVT_F64, OVM_TYPE_I32)) + C(OVM_TYPED_INSTR(OVMI_CVT_F64, OVM_TYPE_I64)) + C(OVM_TYPED_INSTR(OVMI_CVT_F64, OVM_TYPE_F32)) default: snprintf(buf, 64, "unknown (%d)", full_instr); @@ -293,14 +329,14 @@ void ovm_program_print_instructions(ovm_program_t *program, i32 start_instr, i32 } ovm_instr_t instr = program->code[i]; - printf("%48s | r=%02d a=%02d b=%02d i=%d f=%f l=%ld d=%lf\n", ovm_instr_name(instr.full_instr), instr.r, instr.a, instr.b, instr.i, instr.f, instr.l, instr.d); + printf("%50s | r=%02d a=%02d b=%02d i=%d f=%f l=%ld d=%lf\n", ovm_instr_name(instr.full_instr), instr.r, instr.a, instr.b, instr.i, instr.f, instr.l, instr.d); } } void ovm_raw_print_instructions(i32 instr_count, ovm_instr_t *instrs) { fori (i, 0, instr_count) { ovm_instr_t instr = instrs[i]; - printf("%48s | r=%02d a=%02d b=%02d i=%d f=%f l=%ld d=%lf\n", ovm_instr_name(instr.full_instr), instr.r, instr.a, instr.b, instr.i, instr.f, instr.l, instr.d); + printf("%50s | r=%02d a=%02d b=%02d i=%d f=%f l=%ld d=%lf\n", ovm_instr_name(instr.full_instr), instr.r, instr.a, instr.b, instr.i, instr.f, instr.l, instr.d); } } @@ -335,7 +371,10 @@ void ovm_engine_memory_copy(ovm_engine_t *engine, i64 target, void *data, i64 si // // State -ovm_state_t *ovm_state_new(ovm_engine_t *engine) { +// +// This takes in a program because it needs to know how many registers to allocate. +// Should there be another mechanism for this? or is this the most concise way? +ovm_state_t *ovm_state_new(ovm_engine_t *engine, ovm_program_t *program) { ovm_store_t *store = engine->store; ovm_state_t *state = bh_alloc_item(store->heap_allocator, ovm_state_t); @@ -346,6 +385,8 @@ ovm_state_t *ovm_state_new(ovm_engine_t *engine) { bh_arr_new(store->heap_allocator, state->numbered_values, 64); bh_arr_new(store->heap_allocator, state->params, 16); bh_arr_new(store->heap_allocator, state->stack_frames, 32); + bh_arr_new(store->heap_allocator, state->registers, program->register_count); + bh_arr_insert_end(state->registers, program->register_count); return state; } @@ -356,6 +397,7 @@ void ovm_state_delete(ovm_state_t *state) { bh_arr_free(state->numbered_values); bh_arr_free(state->params); bh_arr_free(state->stack_frames); + bh_arr_free(state->registers); bh_free(store->heap_allocator, state); } @@ -364,7 +406,7 @@ void ovm_state_delete(ovm_state_t *state) { // // Function calling -static void ovm__func_setup_stack_frame(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *program, i32 func_idx, i32 result_number) { +static inline void ovm__func_setup_stack_frame(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *program, i32 func_idx, i32 result_number) { ovm_func_t *func = &program->funcs[func_idx]; // @@ -400,7 +442,8 @@ ovm_value_t ovm_func_call(ovm_engine_t *engine, ovm_state_t *state, ovm_program_ state->pc = program->funcs[func_idx].start_instr; ovm_run_code(engine, state, program); - return state->numbered_values[state->value_number_offset--]; + state->value_number_offset -= 1; + return bh_arr_pop(state->numbered_values); } @@ -650,6 +693,16 @@ void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *progr break; } + case OVMI_REG_GET: { + VAL(instr.r) = state->registers[instr.a]; + break; + } + + case OVMI_REG_SET: { + state->registers[instr.r] = VAL(instr.a); + break; + } + case OVMI_PARAM: bh_arr_push(state->params, VAL(instr.a)); break; @@ -703,6 +756,7 @@ void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *progr bh_arr_set_length(state->params, 0); \ \ if (OVM_INSTR_TYPE(instr) != OVM_TYPE_NONE) { \ + assert(OVM_INSTR_TYPE(instr) == result.type); \ VAL(instr.r) = result; \ } @@ -734,7 +788,44 @@ void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *progr case OVMI_BRI: state->pc += VAL(instr.a).i32; break; case OVMI_BR_NZ: if (VAL(instr.b).i32 != 0) state->pc += instr.a; break; case OVMI_BRI_NZ: if (VAL(instr.b).i32 != 0) state->pc += VAL(instr.a).i32; break; + case OVMI_BR_Z: if (VAL(instr.b).i32 == 0) state->pc += instr.a; break; + case OVMI_BRI_Z: if (VAL(instr.b).i32 == 0) state->pc += VAL(instr.a).i32; break; + + +#define CVT(stype, dtype, otype, ctype) \ + VAL(instr.r).type = otype; \ + VAL(instr.r).dtype = (ctype) VAL(instr.a).stype; \ + break + + case OVM_TYPED_INSTR(OVMI_CVT_I8, OVM_TYPE_I16): CVT(i8, i16, OVM_TYPE_I16, u16); + case OVM_TYPED_INSTR(OVMI_CVT_I8, OVM_TYPE_I32): CVT(i8, i32, OVM_TYPE_I32, u32); + case OVM_TYPED_INSTR(OVMI_CVT_I8, OVM_TYPE_I64): CVT(i8, i64, OVM_TYPE_I64, u64); + + case OVM_TYPED_INSTR(OVMI_CVT_I16, OVM_TYPE_I8): CVT(i16, i8, OVM_TYPE_I8, u8); + case OVM_TYPED_INSTR(OVMI_CVT_I16, OVM_TYPE_I32): CVT(i16, i32, OVM_TYPE_I32, u32); + case OVM_TYPED_INSTR(OVMI_CVT_I16, OVM_TYPE_I64): CVT(i16, i64, OVM_TYPE_I64, u64); + + case OVM_TYPED_INSTR(OVMI_CVT_I32, OVM_TYPE_I8): CVT(i32, i8, OVM_TYPE_I8, u8); + case OVM_TYPED_INSTR(OVMI_CVT_I32, OVM_TYPE_I16): CVT(i32, i16, OVM_TYPE_I16, u16); + case OVM_TYPED_INSTR(OVMI_CVT_I32, OVM_TYPE_I64): CVT(i32, i64, OVM_TYPE_I64, u64); + case OVM_TYPED_INSTR(OVMI_CVT_I32, OVM_TYPE_F32): CVT(i32, f32, OVM_TYPE_F32, f32); + case OVM_TYPED_INSTR(OVMI_CVT_I32, OVM_TYPE_F64): CVT(i32, f64, OVM_TYPE_F64, f64); + + case OVM_TYPED_INSTR(OVMI_CVT_I64, OVM_TYPE_I8): CVT(i64, i8, OVM_TYPE_I8, u8); + case OVM_TYPED_INSTR(OVMI_CVT_I64, OVM_TYPE_I16): CVT(i64, i16, OVM_TYPE_I16, u16); + case OVM_TYPED_INSTR(OVMI_CVT_I64, OVM_TYPE_I32): CVT(i64, i32, OVM_TYPE_I32, u32); + case OVM_TYPED_INSTR(OVMI_CVT_I64, OVM_TYPE_F32): CVT(i64, f32, OVM_TYPE_F32, f32); + case OVM_TYPED_INSTR(OVMI_CVT_I64, OVM_TYPE_F64): CVT(i64, f64, OVM_TYPE_F64, f64); + + case OVM_TYPED_INSTR(OVMI_CVT_F32, OVM_TYPE_I32): CVT(f32, i32, OVM_TYPE_I32, u32); + case OVM_TYPED_INSTR(OVMI_CVT_F32, OVM_TYPE_I64): CVT(f32, f32, OVM_TYPE_I64, u64); + case OVM_TYPED_INSTR(OVMI_CVT_F32, OVM_TYPE_F64): CVT(f32, f64, OVM_TYPE_F64, f64); + + case OVM_TYPED_INSTR(OVMI_CVT_F64, OVM_TYPE_I32): CVT(f64, i32, OVM_TYPE_I32, u32); + case OVM_TYPED_INSTR(OVMI_CVT_F64, OVM_TYPE_I64): CVT(f64, i64, OVM_TYPE_I64, u64); + case OVM_TYPED_INSTR(OVMI_CVT_F64, OVM_TYPE_F32): CVT(f64, f32, OVM_TYPE_F32, f32); +#undef CVT default: printf("ERROR:\n"); ovm_program_print_instructions(program, state->pc - 1, 1); diff --git a/test.asm b/test.asm index d4b2e34..27fc31e 100644 --- a/test.asm +++ b/test.asm @@ -1,6 +1,9 @@ .native_func dummy 0 -.native_func print_int 1 +.native_func print 1 +.native_func sin 1 + +.register stack_ptr .func add 2 add.i32 %2, %0, %1 @@ -8,32 +11,52 @@ .func count 1 imm.i32 %1, 1 + imm.i32 %2, 5 - :loop + loop: param %0 - native_call print_int + native_call print sub.i32 %0, %0, %1 - br_nz loop, %0 - br skip + eq.i32 %3, %0, %2 + br_z loop, %3 + + // br skip imm.i32 %1, 123 param %1 - native_call print_int - :skip + native_call print + skip: return .func main 0 + reg.get %10, stack_ptr + imm.i32 %0, 1 imm.i32 %1, 2 param %0 param %1 call.i32 %2, add param %2 - native_call print_int + native_call print imm.i32 %3, 10 param %3 call count + reg.set stack_ptr, %10 return +.func sin_test 0 + imm.f32 %0, 3.14159265f + imm.f32 %1, 0.5f + mul.f32 %2, %0, %1 + + param %2 + native_call.f32 %3, sin + + param %3 + native_call print + + return + +