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
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)) ...
+
enum token_type_t {
token_none,
token_newline,
+
token_integer,
+ token_integer_long,
+ token_float,
+ token_float_double,
+
token_command,
token_symbol,
token_register,
// 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);
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);
i32 param_count;
i32 value_number_count;
-
- // return type
};
ovm_func_t *ovm_func_new();
#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
#include "vm.h"
+#include <math.h>
+
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");
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);
%%
\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)
.
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;
//
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;
{ "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 },
{ "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) {
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) {
switch (patch.instr) {
case OVMI_BR:
+ case OVMI_BR_Z:
case OVMI_BR_NZ:
bh_arr_push(label_patches, patch);
break;
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));
}
}
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);
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);
}
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);
}
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];
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);
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);
}
char *output_file = argv[2];
parse(input_file);
- patch_calls();
+ patch();
write_file(output_file);
}
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),
(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
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] =
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,
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;
#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
#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 */
{
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];
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();
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];
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;
}
#define YYTABLES_NAME "yytables"
-#line 55 "src/tools/asm.l"
+#line 59 "src/tools/asm.l"
token_t asm_lexer_peek_token() {
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) {
}
}
}
+
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);
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))
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);
}
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);
}
}
//
// 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);
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;
}
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);
}
//
// 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];
//
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);
}
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;
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; \
}
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);
.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
.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
+
+