};
};
-#define OVM_INSTR_TYPE(instr) ((instr).full_instr >> 24)
-#define OVM_INSTR_INSTR(instr) ((instr).full_instr & 0xffffff)
-#define OVM_INSTR_MASK 0xff
+#define OVM_INSTR_TYPE(instr) ((instr).full_instr & 0x7)
+#define OVM_INSTR_INSTR(instr) (((instr).full_instr >> 3) & 0xff)
+#define OVM_INSTR_MASK 0x7ff
#define OVMI_ATOMIC 0x00800000 // Flag an instruction as atomic
#define OVMI_REG_SET 0x17 // #r = %a
#define OVMI_IDX_ARR 0x18 // %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_CALLI 0x33 // %r = %a(...)
-
-#define OVMI_BR 0x40 // br pc + a // Relative branching
-#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)
-#define OVMI_ROTL 0x53 // %r = rotl(%a, %b)
-#define OVMI_ROTR 0x54 // %r = rotr(%a, %b)
+#define OVMI_LT 0x19 // %r = %a < %b
+#define OVMI_LT_S 0x1a // %r = %a < %b
+#define OVMI_LE 0x1b // %r = %a <= %b
+#define OVMI_LE_S 0x1c // %r = %a <= %b
+#define OVMI_EQ 0x1d // %r = %a == %b
+#define OVMI_GE 0x1e // %r = %a >= %b
+#define OVMI_GE_S 0x1f // %r = %a >= %b
+#define OVMI_GT 0x20 // %r = %a > %b
+#define OVMI_GT_S 0x21 // %r = %a > %b
+#define OVMI_NE 0x22 // %r = %a != %b
+
+#define OVMI_PARAM 0x23 // push %a
+#define OVMI_RETURN 0x24 // return %a
+#define OVMI_CALL 0x25 // %r = a(...)
+#define OVMI_CALLI 0x26 // %r = %a(...)
+
+#define OVMI_BR 0x27 // br pc + a // Relative branching
+#define OVMI_BR_Z 0x28 // br pc + a if %b == 0
+#define OVMI_BR_NZ 0x29 // br pc + a if %b != 0
+#define OVMI_BRI 0x2a // br pc + %a // Relative branching
+#define OVMI_BRI_Z 0x2b // br pc + %a if %b == 0
+#define OVMI_BRI_NZ 0x2c // br pc + %a if %b != 0
+
+#define OVMI_CLZ 0x2d // %r = clz(%a)
+#define OVMI_CTZ 0x2e // %r = ctr(%a)
+#define OVMI_POPCNT 0x2f // %r = popcnt(%a)
+#define OVMI_ROTL 0x30 // %r = rotl(%a, %b)
+#define OVMI_ROTR 0x31 // %r = rotr(%a, %b)
// These instructions are only implemented for floats.
-#define OVMI_ABS 0x55 // %r = |%a|
-#define OVMI_NEG 0x56 // %r = -%a
-#define OVMI_CEIL 0x57 // %r = ceil(%a)
-#define OVMI_FLOOR 0x58 // %r = floor(%a)
-#define OVMI_TRUNC 0x59 // %r = trunc(%a)
-#define OVMI_NEAREST 0x5A // %r = nearest(%a)
-#define OVMI_SQRT 0x5B // %r = sqrt(%a)
-#define OVMI_MIN 0x5C // %r = min(%a, %b)
-#define OVMI_MAX 0x5D // %r = max(%a, %b)
-#define OVMI_COPYSIGN 0x5E // %r = copysign(%a, %b)
+#define OVMI_ABS 0x32 // %r = |%a|
+#define OVMI_NEG 0x33 // %r = -%a
+#define OVMI_CEIL 0x34 // %r = ceil(%a)
+#define OVMI_FLOOR 0x35 // %r = floor(%a)
+#define OVMI_TRUNC 0x36 // %r = trunc(%a)
+#define OVMI_NEAREST 0x37 // %r = nearest(%a)
+#define OVMI_SQRT 0x38 // %r = sqrt(%a)
+#define OVMI_MIN 0x39 // %r = min(%a, %b)
+#define OVMI_MAX 0x3a // %r = max(%a, %b)
+#define OVMI_COPYSIGN 0x3b // %r = copysign(%a, %b)
// For conversion operations, the "type" of the instruction is
// destination type, the type in the name is the source type.
//
// There are a couple of cast operations that are not available,
// such as unsigned conversion from 32-bit integers to floats.
-#define OVMI_CVT_I8 0x60 // %r = (t) %a
-#define OVMI_CVT_I8_S 0x61 // %r = (t) %a (sign aware)
-#define OVMI_CVT_I16 0x62 // %r = (t) %a
-#define OVMI_CVT_I16_S 0x63 // %r = (t) %a (sign aware)
-#define OVMI_CVT_I32 0x64 // %r = (t) %a
-#define OVMI_CVT_I32_S 0x65 // %r = (t) %a (sign aware)
-#define OVMI_CVT_I64 0x66 // %r = (t) %a
-#define OVMI_CVT_I64_S 0x67 // %r = (t) %a (sign aware)
-#define OVMI_CVT_F32 0x68 // %r = (t) %a
-#define OVMI_CVT_F32_S 0x69 // %r = (t) %a (sign aware)
-#define OVMI_CVT_F64 0x6A // %r = (t) %a
-#define OVMI_CVT_F64_S 0x6B // %r = (t) %a (sign aware)
-#define OVMI_TRANSMUTE_I32 0x6C // %r = *(t *) &%a (reinterpret bytes)
-#define OVMI_TRANSMUTE_I64 0x6D // %r = *(t *) &%a (reinterpret bytes)
-#define OVMI_TRANSMUTE_F32 0x6E // %r = *(t *) &%a (reinterpret bytes)
-#define OVMI_TRANSMUTE_F64 0x6F // %r = *(t *) &%a (reinterpret bytes)
-
-#define OVMI_CMPXCHG 0x70 // %r = %r == %a ? %b : %r
-
-#define OVMI_BREAK 0xff
+#define OVMI_CVT_I8 0x3c // %r = (t) %a
+#define OVMI_CVT_I8_S 0x3d // %r = (t) %a (sign aware)
+#define OVMI_CVT_I16 0x3e // %r = (t) %a
+#define OVMI_CVT_I16_S 0x3f // %r = (t) %a (sign aware)
+#define OVMI_CVT_I32 0x40 // %r = (t) %a
+#define OVMI_CVT_I32_S 0x41 // %r = (t) %a (sign aware)
+#define OVMI_CVT_I64 0x42 // %r = (t) %a
+#define OVMI_CVT_I64_S 0x43 // %r = (t) %a (sign aware)
+#define OVMI_CVT_F32 0x44 // %r = (t) %a
+#define OVMI_CVT_F32_S 0x45 // %r = (t) %a (sign aware)
+#define OVMI_CVT_F64 0x46 // %r = (t) %a
+#define OVMI_CVT_F64_S 0x47 // %r = (t) %a (sign aware)
+#define OVMI_TRANSMUTE_I32 0x48 // %r = *(t *) &%a (reinterpret bytes)
+#define OVMI_TRANSMUTE_I64 0x49 // %r = *(t *) &%a (reinterpret bytes)
+#define OVMI_TRANSMUTE_F32 0x4a // %r = *(t *) &%a (reinterpret bytes)
+#define OVMI_TRANSMUTE_F64 0x4b // %r = *(t *) &%a (reinterpret bytes)
+
+#define OVMI_CMPXCHG 0x4c // %r = %r == %a ? %b : %r
+
+#define OVMI_BREAK 0x4d
//
// OVM_TYPED_INSTR(OVMI_ADD, OVM_TYPE_I32) == instruction for adding i32s
//
-#define OVM_TYPED_INSTR(instr, type) (((type) << 24) | (instr))
+#define OVM_TYPED_INSTR(instr, type) (((instr) << 3) | (type))
#endif
void ovm_code_builder_add_break(ovm_code_builder_t *builder) {
ovm_instr_t break_ = {0};
- break_.full_instr = OVMI_BREAK;
+ break_.full_instr = OVM_TYPED_INSTR(OVMI_BREAK, OVM_TYPE_NONE);
debug_info_builder_emit_location(builder->debug_builder);
ovm_program_add_instructions(builder->program, 1, &break_);
}
void ovm_code_builder_add_branch(ovm_code_builder_t *builder, i32 label_idx) {
ovm_instr_t branch_instr = {0};
- branch_instr.full_instr = OVMI_BR;
+ branch_instr.full_instr = OVM_TYPED_INSTR(OVMI_BR, OVM_TYPE_NONE);
branch_instr.a = -1;
branch_patch_t patch;
void ovm_code_builder_add_cond_branch(ovm_code_builder_t *builder, i32 label_idx, bool branch_if_true, bool targets_else) {
ovm_instr_t branch_instr = {0};
if (branch_if_true) {
- branch_instr.full_instr = OVMI_BR_NZ;
+ branch_instr.full_instr = OVM_TYPED_INSTR(OVMI_BR_NZ, OVM_TYPE_NONE);
} else {
- branch_instr.full_instr = OVMI_BR_Z;
+ branch_instr.full_instr = OVM_TYPED_INSTR(OVMI_BR_Z, OVM_TYPE_NONE);
}
branch_instr.a = -1;
instrs[1].a = index_register;
instrs[1].b = tmp_register;
- instrs[2].full_instr = OVMI_BR_Z;
+ instrs[2].full_instr = OVM_TYPED_INSTR(OVMI_BR_Z, OVM_TYPE_NONE);
instrs[2].a = -1;
instrs[2].b = tmp_register;
- instrs[3].full_instr = OVMI_IDX_ARR;
+ instrs[3].full_instr = OVM_TYPED_INSTR(OVMI_IDX_ARR, OVM_TYPE_NONE);
instrs[3].r = tmp_register;
instrs[3].a = table_idx;
instrs[3].b = index_register;
- instrs[4].full_instr = OVMI_BRI;
+ instrs[4].full_instr = OVM_TYPED_INSTR(OVMI_BRI, OVM_TYPE_NONE);
instrs[4].a = tmp_register;
POP_VALUE(builder);
void ovm_code_builder_add_return(ovm_code_builder_t *builder) {
ovm_instr_t instr = {0};
- instr.full_instr = OVMI_RETURN;
+ instr.full_instr = OVM_TYPED_INSTR(OVMI_RETURN, OVM_TYPE_NONE);
i32 values_on_stack = bh_arr_length(builder->execution_stack);
assert(values_on_stack == 0 || values_on_stack == 1);
fori (i, 0, param_count) {
ovm_instr_t param_instr = {0};
- param_instr.full_instr = OVMI_PARAM;
+ param_instr.full_instr = OVM_TYPED_INSTR(OVMI_PARAM, OVM_TYPE_NONE);
param_instr.a = flipped_params[param_count - 1 - i];
debug_info_builder_emit_location(builder->debug_builder);
ovm_code_builder_add_params(builder, param_count);
ovm_instr_t call_instr = {0};
- call_instr.full_instr = OVMI_CALL;
+ call_instr.full_instr = OVM_TYPED_INSTR(OVMI_CALL, OVM_TYPE_NONE);
call_instr.a = func_idx;
call_instr.r = -1;
ovm_instr_t call_instrs[2] = {0};
// idxarr %k, table, %j
- call_instrs[0].full_instr = OVMI_IDX_ARR;
+ call_instrs[0].full_instr = OVM_TYPED_INSTR(OVMI_IDX_ARR, OVM_TYPE_NONE);
call_instrs[0].r = NEXT_VALUE(builder);
call_instrs[0].a = builder->func_table_arr_idx;
call_instrs[0].b = POP_VALUE(builder);
- call_instrs[1].full_instr = OVMI_CALLI;
+ call_instrs[1].full_instr = OVM_TYPED_INSTR(OVMI_CALLI, OVM_TYPE_NONE);
call_instrs[1].a = call_instrs[0].r;
call_instrs[1].r = -1;
void ovm_code_builder_add_local_get(ovm_code_builder_t *builder, i32 local_idx) {
ovm_instr_t instr = {0};
- instr.full_instr = OVMI_MOV;
+ instr.full_instr = OVM_TYPED_INSTR(OVMI_MOV, OVM_TYPE_NONE);
instr.r = NEXT_VALUE(builder);
instr.a = local_idx; // This makes the assumption that the params will be in
// the lower "address space" of the value numbers. This
void ovm_code_builder_add_local_set(ovm_code_builder_t *builder, i32 local_idx) {
ovm_instr_t instr = {0};
- instr.full_instr = OVMI_MOV;
+ instr.full_instr = OVM_TYPED_INSTR(OVMI_MOV, OVM_TYPE_NONE);
instr.r = local_idx; // This makes the assumption that the params will be in
// the lower "address space" of the value numbers. This
// will be true for web assembly, because that's how it
void ovm_code_builder_add_local_tee(ovm_code_builder_t *builder, i32 local_idx) {
ovm_instr_t instr = {0};
- instr.full_instr = OVMI_MOV;
+ instr.full_instr = OVM_TYPED_INSTR(OVMI_MOV, OVM_TYPE_NONE);
instr.r = local_idx; // This makes the assumption that the params will be in
// the lower "address space" of the value numbers. This
// will be true for web assembly, because that's how it
void ovm_code_builder_add_register_get(ovm_code_builder_t *builder, i32 reg_idx) {
ovm_instr_t instr = {0};
- instr.full_instr = OVMI_REG_GET;
+ instr.full_instr = OVM_TYPED_INSTR(OVMI_REG_GET, OVM_TYPE_NONE);
instr.r = NEXT_VALUE(builder);
instr.a = reg_idx;
void ovm_code_builder_add_register_set(ovm_code_builder_t *builder, i32 reg_idx) {
ovm_instr_t instr = {0};
- instr.full_instr = OVMI_REG_SET;
+ instr.full_instr = OVM_TYPED_INSTR(OVMI_REG_SET, OVM_TYPE_NONE);
instr.r = reg_idx;
instr.a = POP_VALUE(builder);
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.full_instr = OVMI_ATOMIC | OVM_TYPED_INSTR(OVMI_CMPXCHG, ovm_type);
cmpxchg_instr.b = POP_VALUE(builder);
cmpxchg_instr.a = POP_VALUE(builder);
cmpxchg_instr.r = POP_VALUE(builder);
instrs[1].b = instrs[0].r;
// cmpxchg.x %m, %n
- instrs[2].full_instr = OVM_TYPED_INSTR(OVMI_ATOMIC | OVMI_CMPXCHG, ovm_type);
+ instrs[2].full_instr = OVMI_ATOMIC | OVM_TYPED_INSTR(OVMI_CMPXCHG, ovm_type);
instrs[2].r = instrs[1].r;
instrs[2].a = expected_reg;
instrs[2].b = value_reg;
void ovm_code_builder_add_memory_copy(ovm_code_builder_t *builder) {
ovm_instr_t instr = {0};
- instr.full_instr = OVMI_COPY;
+ instr.full_instr = OVM_TYPED_INSTR(OVMI_COPY, OVM_TYPE_NONE);
instr.b = POP_VALUE(builder);
instr.a = POP_VALUE(builder);
instr.r = POP_VALUE(builder);
void ovm_code_builder_add_memory_fill(ovm_code_builder_t *builder) {
ovm_instr_t instr = {0};
- instr.full_instr = OVMI_FILL;
+ instr.full_instr = OVM_TYPED_INSTR(OVMI_FILL, OVM_TYPE_NONE);
instr.b = POP_VALUE(builder);
instr.a = POP_VALUE(builder);
instr.r = POP_VALUE(builder);
// CopyNPaste from _add_load
void ovm_code_builder_add_atomic_load(ovm_code_builder_t *builder, u32 ovm_type, i32 offset) {
ovm_instr_t load_instr = {0};
- load_instr.full_instr = OVM_TYPED_INSTR(OVMI_ATOMIC | OVMI_LOAD, ovm_type);
+ load_instr.full_instr = OVMI_ATOMIC | OVM_TYPED_INSTR(OVMI_LOAD, ovm_type);
load_instr.b = offset;
load_instr.a = POP_VALUE(builder);
load_instr.r = NEXT_VALUE(builder);
// CopyNPaste from _add_store
void ovm_code_builder_add_atomic_store(ovm_code_builder_t *builder, u32 ovm_type, i32 offset) {
ovm_instr_t store_instr = {0};
- store_instr.full_instr = OVM_TYPED_INSTR(OVMI_ATOMIC | OVMI_STORE, ovm_type);
+ store_instr.full_instr = OVMI_ATOMIC | OVM_TYPED_INSTR(OVMI_STORE, ovm_type);
store_instr.b = offset;
store_instr.a = POP_VALUE(builder);
store_instr.r = POP_VALUE(builder);
}
+static char *ovm_instr_name(i32 full_instr) {
+ return "";
+}
+
+#if 0
static char *ovm_instr_name(i32 full_instr) {
#define C(...) \
case __VA_ARGS__: return #__VA_ARGS__; \
return buf;
}
}
+#endif
void ovm_program_print_instructions(ovm_program_t *program, i32 start_instr, i32 instr_count) {
fori (i, start_instr, start_instr + instr_count) {
#define NEXT_OP \
if (instr->full_instr & OVMI_ATOMIC) pthread_mutex_unlock(&state->engine->atomic_mutex); \
- __ovm_debug_hook(state->engine, state); \
+ if (state->debug) __ovm_debug_hook(state->engine, state); \
instr = &code[state->pc++]; \
if (instr->full_instr & OVMI_ATOMIC) pthread_mutex_lock(&state->engine->atomic_mutex); \
return ovmi_dispatch[instr->full_instr & OVM_INSTR_MASK](instr, state, memory, code);
//
#define OVM_OP_EXEC(name, op) \
- OVMI_INSTR_EXEC(ovmi_exec_##name) { \
- switch (OVM_INSTR_TYPE(*instr)) { \
- OVM_OP(OVM_TYPE_I8 , op, i8) \
- OVM_OP(OVM_TYPE_I16, op, i16) \
- OVM_OP(OVM_TYPE_I32, op, i32) \
- OVM_OP(OVM_TYPE_I64, op, i64) \
- OVM_OP(OVM_TYPE_F32, op, f32) \
- OVM_OP(OVM_TYPE_F64, op, f64) \
- } \
- NEXT_OP; \
- }
+ OVMI_INSTR_EXEC(ovmi_exec_##name##_i32) { OVM_OP(OVM_TYPE_I32, op, i32); NEXT_OP; } \
+ OVMI_INSTR_EXEC(ovmi_exec_##name##_i64) { OVM_OP(OVM_TYPE_I64, op, i64); NEXT_OP; } \
+ OVMI_INSTR_EXEC(ovmi_exec_##name##_f32) { OVM_OP(OVM_TYPE_F32, op, f32); NEXT_OP; } \
+ OVMI_INSTR_EXEC(ovmi_exec_##name##_f64) { OVM_OP(OVM_TYPE_F64, op, f64); NEXT_OP; }
#define OVM_OP_UNSIGNED_EXEC(name, op) \
- OVMI_INSTR_EXEC(ovmi_exec_##name) { \
- switch (OVM_INSTR_TYPE(*instr)) { \
- OVM_OP(OVM_TYPE_I8 , op, u8) \
- OVM_OP(OVM_TYPE_I16, op, u16) \
- OVM_OP(OVM_TYPE_I32, op, u32) \
- OVM_OP(OVM_TYPE_I64, op, u64) \
- OVM_OP(OVM_TYPE_F32, op, f32) \
- OVM_OP(OVM_TYPE_F64, op, f64) \
- } \
- NEXT_OP; \
- }
+ OVMI_INSTR_EXEC(ovmi_exec_##name##_i32) { OVM_OP(OVM_TYPE_I32, op, u32); NEXT_OP; } \
+ OVMI_INSTR_EXEC(ovmi_exec_##name##_i64) { OVM_OP(OVM_TYPE_I64, op, u64); NEXT_OP; } \
+ OVMI_INSTR_EXEC(ovmi_exec_##name##_f32) { OVM_OP(OVM_TYPE_F32, op, f32); NEXT_OP; } \
+ OVMI_INSTR_EXEC(ovmi_exec_##name##_f64) { OVM_OP(OVM_TYPE_F64, op, f64); NEXT_OP; }
#define OVM_OP_INTEGER_EXEC(name, op) \
- OVMI_INSTR_EXEC(ovmi_exec_##name) { \
- switch (OVM_INSTR_TYPE(*instr)) { \
- OVM_OP(OVM_TYPE_I8 , op, i8) \
- OVM_OP(OVM_TYPE_I16, op, i16) \
- OVM_OP(OVM_TYPE_I32, op, i32) \
- OVM_OP(OVM_TYPE_I64, op, i64) \
- } \
- NEXT_OP; \
- }
+ OVMI_INSTR_EXEC(ovmi_exec_##name##_i32) { OVM_OP(OVM_TYPE_I32, op, i32); NEXT_OP; } \
+ OVMI_INSTR_EXEC(ovmi_exec_##name##_i64) { OVM_OP(OVM_TYPE_I64, op, i64); NEXT_OP; }
#define OVM_OP_INTEGER_UNSIGNED_EXEC(name, op) \
- OVMI_INSTR_EXEC(ovmi_exec_##name) { \
- switch (OVM_INSTR_TYPE(*instr)) { \
- OVM_OP(OVM_TYPE_I8 , op, u8) \
- OVM_OP(OVM_TYPE_I16, op, u16) \
- OVM_OP(OVM_TYPE_I32, op, u32) \
- OVM_OP(OVM_TYPE_I64, op, u64) \
- } \
- NEXT_OP; \
- }
+ OVMI_INSTR_EXEC(ovmi_exec_##name##_i32) { OVM_OP(OVM_TYPE_I32, op, u32); NEXT_OP; } \
+ OVMI_INSTR_EXEC(ovmi_exec_##name##_i64) { OVM_OP(OVM_TYPE_I64, op, u64); NEXT_OP; }
#define OVM_OP_FLOAT_EXEC(name, op) \
- OVMI_INSTR_EXEC(ovmi_exec_##name) { \
- switch (OVM_INSTR_TYPE(*instr)) { \
- OVM_OP(OVM_TYPE_F32, op, f32) \
- OVM_OP(OVM_TYPE_F64, op, f64) \
- } \
- NEXT_OP; \
- }
+ OVMI_INSTR_EXEC(ovmi_exec_##name##_f32) { OVM_OP(OVM_TYPE_F32, op, f32); NEXT_OP; } \
+ OVMI_INSTR_EXEC(ovmi_exec_##name##_f64) { OVM_OP(OVM_TYPE_F64, op, f64); NEXT_OP; }
+
#define OVM_OP(t, op, ctype) \
- case t: \
- ovm_assert(VAL(instr->a).type == t && VAL(instr->b).type == t); \
- VAL(instr->r).ctype = VAL(instr->a).ctype op VAL(instr->b).ctype; \
- VAL(instr->r).type = t; \
- break;
+ ovm_assert(VAL(instr->a).type == t && VAL(instr->b).type == t); \
+ VAL(instr->r).ctype = VAL(instr->a).ctype op VAL(instr->b).ctype; \
+ VAL(instr->r).type = t;
OVM_OP_EXEC(add, +)
OVM_OP_EXEC(sub, -)
#undef OVM_OP
#define OVM_OP(t, func, ctype) \
- case t: \
- ovm_assert(VAL(instr->a).type == t && VAL(instr->b).type == t); \
- VAL(instr->r).ctype = func( VAL(instr->a).ctype, VAL(instr->b).ctype ); \
- VAL(instr->r).type = t; \
- break;
-
-OVMI_INSTR_EXEC(ovmi_exec_rotl) {
- switch (OVM_INSTR_TYPE(*instr)) {
- OVM_OP(OVM_TYPE_I8 , __rolb, u8)
- OVM_OP(OVM_TYPE_I16, __rolw, u16)
- OVM_OP(OVM_TYPE_I32, __rold, u32)
- OVM_OP(OVM_TYPE_I64, __rolq, u64)
- }
- NEXT_OP;
-}
+ ovm_assert(VAL(instr->a).type == t && VAL(instr->b).type == t); \
+ VAL(instr->r).ctype = func( VAL(instr->a).ctype, VAL(instr->b).ctype ); \
+ VAL(instr->r).type = t;
-OVMI_INSTR_EXEC(ovmi_exec_rotr) {
- switch (OVM_INSTR_TYPE(*instr)) {
- OVM_OP(OVM_TYPE_I8 , __rorb, u8)
- OVM_OP(OVM_TYPE_I16, __rorw, u16)
- OVM_OP(OVM_TYPE_I32, __rord, u32)
- OVM_OP(OVM_TYPE_I64, __rorq, u64)
- }
- NEXT_OP;
-}
+OVMI_INSTR_EXEC(ovmi_exec_rotl_i32) { OVM_OP(OVM_TYPE_I32, __rold, u32); NEXT_OP; }
+OVMI_INSTR_EXEC(ovmi_exec_rotl_i64) { OVM_OP(OVM_TYPE_I64, __rolq, u64); NEXT_OP; }
+OVMI_INSTR_EXEC(ovmi_exec_rotr_i32) { OVM_OP(OVM_TYPE_I32, __rord, u32); NEXT_OP; }
+OVMI_INSTR_EXEC(ovmi_exec_rotr_i64) { OVM_OP(OVM_TYPE_I64, __rorq, u64); NEXT_OP; }
OVM_OP_FLOAT_EXEC(min, bh_min)
OVM_OP_FLOAT_EXEC(max, bh_max)
#define OVM_OP(t, op, ctype) \
- case t: \
- ovm_assert(VAL(instr->a).type == t); \
- VAL(instr->r).type = t; \
- VAL(instr->r).ctype = (ctype) op (VAL(instr->a).ctype); \
- break;
-
-OVMI_INSTR_EXEC(ovmi_exec_clz) {
- switch (OVM_INSTR_TYPE(*instr)) {
- OVM_OP(OVM_TYPE_I8 , __builtin_clz, u8)
- OVM_OP(OVM_TYPE_I16, __builtin_clz, u16)
- OVM_OP(OVM_TYPE_I32, __builtin_clz, u32)
- OVM_OP(OVM_TYPE_I64, __builtin_clzll, u64)
- }
- NEXT_OP;
-}
+ ovm_assert(VAL(instr->a).type == t); \
+ VAL(instr->r).type = t; \
+ VAL(instr->r).ctype = (ctype) op (VAL(instr->a).ctype);
-OVMI_INSTR_EXEC(ovmi_exec_ctz) {
- switch (OVM_INSTR_TYPE(*instr)) {
- OVM_OP(OVM_TYPE_I8 , __builtin_ctz, u8)
- OVM_OP(OVM_TYPE_I16, __builtin_ctz, u16)
- OVM_OP(OVM_TYPE_I32, __builtin_ctz, u32)
- OVM_OP(OVM_TYPE_I64, __builtin_ctzll, u64)
- }
- NEXT_OP;
-}
-
-OVMI_INSTR_EXEC(ovmi_exec_popcount) {
- switch (OVM_INSTR_TYPE(*instr)) {
- OVM_OP(OVM_TYPE_I8 , __builtin_popcount, u8)
- OVM_OP(OVM_TYPE_I16, __builtin_popcount, u16)
- OVM_OP(OVM_TYPE_I32, __builtin_popcount, u32)
- OVM_OP(OVM_TYPE_I64, __builtin_popcountll, u64)
- }
- NEXT_OP;
-}
+OVMI_INSTR_EXEC(ovmi_exec_clz_i32) { OVM_OP(OVM_TYPE_I32, __builtin_clz, u32); NEXT_OP; }
+OVMI_INSTR_EXEC(ovmi_exec_clz_i64) { OVM_OP(OVM_TYPE_I64, __builtin_clzll, u64); NEXT_OP; }
+OVMI_INSTR_EXEC(ovmi_exec_ctz_i32) { OVM_OP(OVM_TYPE_I32, __builtin_ctz, u32); NEXT_OP; }
+OVMI_INSTR_EXEC(ovmi_exec_ctz_i64) { OVM_OP(OVM_TYPE_I64, __builtin_ctzll, u64); NEXT_OP; }
+OVMI_INSTR_EXEC(ovmi_exec_popcount_i32) { OVM_OP(OVM_TYPE_I32, __builtin_popcount, u32); NEXT_OP; }
+OVMI_INSTR_EXEC(ovmi_exec_popcount_i64) { OVM_OP(OVM_TYPE_I64, __builtin_popcountll, u64); NEXT_OP; }
OVM_OP_FLOAT_EXEC(abs, __ovm_abs)
OVM_OP_FLOAT_EXEC(neg, -)
#define OVM_OP(t, op, ctype) \
- case t: \
- ovm_assert(VAL(instr->a).type == t && VAL(instr->b).type == t); \
- VAL(instr->r).type = OVM_TYPE_I32; \
- VAL(instr->r).i32 = ((VAL(instr->a).ctype op VAL(instr->b).ctype)) ? 1 : 0; \
- break;
+ ovm_assert(VAL(instr->a).type == t && VAL(instr->b).type == t); \
+ VAL(instr->r).type = OVM_TYPE_I32; \
+ VAL(instr->r).i32 = ((VAL(instr->a).ctype op VAL(instr->b).ctype)) ? 1 : 0;
OVM_OP_EXEC(eq, ==)
OVM_OP_EXEC(ne, !=)
//
#define OVM_IMM(t, dtype, stype) \
- case t: \
- VAL(instr->r).type = t; \
- VAL(instr->r).u64 = 0; \
- VAL(instr->r).dtype = instr->stype; \
- break;
-
-
-OVMI_INSTR_EXEC(ovmi_exec_imm) {
- switch (OVM_INSTR_TYPE(*instr)) {
- OVM_IMM(OVM_TYPE_I8, u8, i);
- OVM_IMM(OVM_TYPE_I16, u16, i);
- OVM_IMM(OVM_TYPE_I32, u32, i);
- OVM_IMM(OVM_TYPE_I64, u64, l);
- OVM_IMM(OVM_TYPE_F32, f32, f);
- OVM_IMM(OVM_TYPE_F64, f64, d);
- }
- NEXT_OP;
-}
+ VAL(instr->r).type = t; \
+ VAL(instr->r).u64 = 0; \
+ VAL(instr->r).dtype = instr->stype;
+
+
+OVMI_INSTR_EXEC(ovmi_exec_imm_i32) { OVM_IMM(OVM_TYPE_I32, u32, i); NEXT_OP; }
+OVMI_INSTR_EXEC(ovmi_exec_imm_i64) { OVM_IMM(OVM_TYPE_I64, u64, l); NEXT_OP; }
+OVMI_INSTR_EXEC(ovmi_exec_imm_f32) { OVM_IMM(OVM_TYPE_F32, f32, f); NEXT_OP; }
+OVMI_INSTR_EXEC(ovmi_exec_imm_f64) { OVM_IMM(OVM_TYPE_F64, f64, d); NEXT_OP; }
#undef OVM_IMM
NEXT_OP;
}
-#define OVM_LOAD(type_, stype) \
- case type_: {\
+#define OVM_LOAD(otype, type_, stype) \
+ OVMI_INSTR_EXEC(ovmi_exec_load_##otype) { \
+ ovm_assert(VAL(instr->a).type == OVM_TYPE_I32); \
+ u32 dest = VAL(instr->a).u32 + (u32) instr->b; \
+ if (dest == 0) __ovm_trigger_exception(state); \
VAL(instr->r).stype = * (stype *) &memory[dest]; \
VAL(instr->r).type = type_; \
- break; \
+ NEXT_OP; \
}
-OVMI_INSTR_EXEC(ovmi_exec_load) {
- ovm_assert(VAL(instr->a).type == OVM_TYPE_I32);
- u32 dest = VAL(instr->a).u32 + (u32) instr->b;
- if (dest == 0) __ovm_trigger_exception(state);
-
- switch (OVM_INSTR_TYPE(*instr)) {
- OVM_LOAD(OVM_TYPE_I8, u8)
- OVM_LOAD(OVM_TYPE_I16, u16)
- OVM_LOAD(OVM_TYPE_I32, u32)
- OVM_LOAD(OVM_TYPE_I64, u64)
- OVM_LOAD(OVM_TYPE_F32, f32)
- OVM_LOAD(OVM_TYPE_F64, f64)
- }
- NEXT_OP;
-}
+OVM_LOAD(i8, OVM_TYPE_I8, u8)
+OVM_LOAD(i16, OVM_TYPE_I16, u16)
+OVM_LOAD(i32, OVM_TYPE_I32, u32)
+OVM_LOAD(i64, OVM_TYPE_I64, u64)
+OVM_LOAD(f32, OVM_TYPE_F32, f32)
+OVM_LOAD(f64, OVM_TYPE_F64, f64)
#undef OVM_LOAD
-#define OVM_STORE(type_, stype) \
- case type_: \
+#define OVM_STORE(otype, type_, stype) \
+ OVMI_INSTR_EXEC(ovmi_exec_store_##otype) { \
+ ovm_assert(VAL(instr->r).type == OVM_TYPE_I32); \
+ u32 dest = VAL(instr->r).u32 + (u32) instr->b; \
+ if (dest == 0) __ovm_trigger_exception(state); \
*(stype *) &memory[dest] = VAL(instr->a).stype; \
- break;
-
+ NEXT_OP; \
+ }
-OVMI_INSTR_EXEC(ovmi_exec_store) {
- ovm_assert(VAL(instr->r).type == OVM_TYPE_I32);
- u32 dest = VAL(instr->r).u32 + (u32) instr->b;
- if (dest == 0) __ovm_trigger_exception(state);
- switch (OVM_INSTR_TYPE(*instr)) {
- OVM_STORE(OVM_TYPE_I8, u8)
- OVM_STORE(OVM_TYPE_I16, u16)
- OVM_STORE(OVM_TYPE_I32, u32)
- OVM_STORE(OVM_TYPE_I64, u64)
- OVM_STORE(OVM_TYPE_F32, f32)
- OVM_STORE(OVM_TYPE_F64, f64)
- }
- NEXT_OP;
-}
+OVM_STORE(i8, OVM_TYPE_I8, u8)
+OVM_STORE(i16, OVM_TYPE_I16, u16)
+OVM_STORE(i32, OVM_TYPE_I32, u32)
+OVM_STORE(i64, OVM_TYPE_I64, u64)
+OVM_STORE(f32, OVM_TYPE_F32, f32)
+OVM_STORE(f64, OVM_TYPE_F64, f64)
#undef OVM_STORE
VAL(instr->r) = tmp_val; \
break
- case OVM_TYPED_INSTR(OVMI_TRANSMUTE_I32, OVM_TYPE_F32): CVT(u32, f32, OVM_TYPE_F32, f32);
- case OVM_TYPED_INSTR(OVMI_TRANSMUTE_I64, OVM_TYPE_F64): CVT(u64, f64, OVM_TYPE_F64, f64);
- case OVM_TYPED_INSTR(OVMI_TRANSMUTE_F32, OVM_TYPE_I32): CVT(f32, u32, OVM_TYPE_I32, u32);
- case OVM_TYPED_INSTR(OVMI_TRANSMUTE_F64, OVM_TYPE_I64): CVT(f64, u64, OVM_TYPE_I64, u64);
+ case OVM_TYPED_INSTR(OVMI_TRANSMUTE_I32, OVM_TYPE_F32): CVT(u32, f32, OVM_TYPE_F32, f32);
+ case OVM_TYPED_INSTR(OVMI_TRANSMUTE_I64, OVM_TYPE_F64): CVT(u64, f64, OVM_TYPE_F64, f64);
+ case OVM_TYPED_INSTR(OVMI_TRANSMUTE_F32, OVM_TYPE_I32): CVT(f32, u32, OVM_TYPE_I32, u32);
+ case OVM_TYPED_INSTR(OVMI_TRANSMUTE_F64, OVM_TYPE_I64): CVT(f64, u64, OVM_TYPE_I64, u64);
#undef CVT
}
//
#define CMPXCHG(otype, ctype) \
- case otype: {\
+ OVMI_INSTR_EXEC(ovmi_exec_cmpxchg_##ctype) { \
if (VAL(instr->r).u32 == 0) __ovm_trigger_exception(state); \
ctype *addr = (ctype *) &memory[VAL(instr->r).u32]; \
\
if (*addr == VAL(instr->a).ctype) { \
*addr = VAL(instr->b).ctype ; \
} \
- break; \
- }
-
-OVMI_INSTR_EXEC(ovmi_exec_cmpxchg) {
- switch (OVM_INSTR_TYPE(*instr)) {
- CMPXCHG(OVM_TYPE_I8, i8)
- CMPXCHG(OVM_TYPE_I16, i16)
- CMPXCHG(OVM_TYPE_I32, i32)
- CMPXCHG(OVM_TYPE_I64, i64)
+ NEXT_OP; \
}
- NEXT_OP;
-}
+CMPXCHG(OVM_TYPE_I32, i32)
+CMPXCHG(OVM_TYPE_I64, i64)
#undef CMPXCHG
// Dispatch table
//
-static ovmi_instr_exec_t ovmi_dispatch[256] = {
- // 0x00
- ovmi_exec_nop,
- ovmi_exec_add,
- ovmi_exec_sub,
- ovmi_exec_mul,
- ovmi_exec_div,
- ovmi_exec_div_s,
- ovmi_exec_rem,
- ovmi_exec_rem_s,
- ovmi_exec_and,
- ovmi_exec_or,
- ovmi_exec_xor,
- ovmi_exec_shl,
- ovmi_exec_shr,
- ovmi_exec_sar,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
-
- // 0x10
- ovmi_exec_imm,
- ovmi_exec_mov,
- ovmi_exec_load,
- ovmi_exec_store,
- ovmi_exec_copy,
- ovmi_exec_fill,
- ovmi_exec_reg_get,
- ovmi_exec_reg_set,
- ovmi_exec_idx_arr,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
-
- // 0x20
- ovmi_exec_lt,
- ovmi_exec_lt_s,
- ovmi_exec_le,
- ovmi_exec_le_s,
- ovmi_exec_eq,
- ovmi_exec_ge,
- ovmi_exec_ge_s,
- ovmi_exec_gt,
- ovmi_exec_gt_s,
- ovmi_exec_ne,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
-
- // 0x30
- ovmi_exec_param,
- ovmi_exec_return,
- ovmi_exec_call,
- ovmi_exec_calli,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
-
- // 0x40
- ovmi_exec_br,
- ovmi_exec_br_z,
- ovmi_exec_br_nz,
- ovmi_exec_bri,
- ovmi_exec_bri_z,
- ovmi_exec_bri_nz,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
-
- // 0x50
- ovmi_exec_clz,
- ovmi_exec_ctz,
- ovmi_exec_popcount,
- ovmi_exec_rotl,
- ovmi_exec_rotr,
- ovmi_exec_abs,
- ovmi_exec_neg,
- ovmi_exec_ceil,
- ovmi_exec_floor,
- ovmi_exec_trunc,
- ovmi_exec_nearest,
- ovmi_exec_sqrt,
- ovmi_exec_min,
- ovmi_exec_max,
- ovmi_exec_copysign,
- ovmi_exec_illegal,
-
- // 0x60
- ovmi_exec_cvt,
- ovmi_exec_cvt,
- ovmi_exec_cvt,
- ovmi_exec_cvt,
- ovmi_exec_cvt,
- ovmi_exec_cvt,
- ovmi_exec_cvt,
- ovmi_exec_cvt,
- ovmi_exec_cvt,
- ovmi_exec_cvt,
- ovmi_exec_cvt,
- ovmi_exec_cvt,
- ovmi_exec_cvt,
- ovmi_exec_cvt,
- ovmi_exec_cvt,
- ovmi_exec_cvt,
-
- // 0x70
- ovmi_exec_cmpxchg,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
- ovmi_exec_illegal,
-
- // 0x80
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
-
- // 0x90
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
-
- // 0xA0
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
-
- // 0xB0
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
-
- // 0xC0
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
-
- // 0xD0
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
-
- // 0xE0
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
-
- // 0xF0
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
- ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal, ovmi_exec_illegal,
+#define IROW_UNTYPED(name) ovmi_exec_##name, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+#define IROW_TYPED(name) NULL, ovmi_exec_##name##_i8, ovmi_exec_##name##_i16, ovmi_exec_##name##_i32, ovmi_exec_##name##_i64, ovmi_exec_##name##_f32, ovmi_exec_##name##_f64, NULL,
+#define IROW_PARTIAL(name) NULL, NULL, NULL, ovmi_exec_##name##_i32, ovmi_exec_##name##_i64, ovmi_exec_##name##_f32, ovmi_exec_##name##_f64, NULL,
+#define IROW_INT(name) NULL, NULL, NULL, ovmi_exec_##name##_i32, ovmi_exec_##name##_i64, NULL, NULL, NULL,
+#define IROW_FLOAT(name) NULL, NULL, NULL, NULL, NULL, ovmi_exec_##name##_f32, ovmi_exec_##name##_f64, NULL,
+#define IROW_SAME(name) ovmi_exec_##name,ovmi_exec_##name,ovmi_exec_##name,ovmi_exec_##name,ovmi_exec_##name,ovmi_exec_##name,ovmi_exec_##name,NULL,
+
+static ovmi_instr_exec_t ovmi_dispatch[] = {
+ IROW_UNTYPED(nop) // 0x00
+ IROW_PARTIAL(add)
+ IROW_PARTIAL(sub)
+ IROW_PARTIAL(mul)
+ IROW_PARTIAL(div)
+ IROW_PARTIAL(div_s)
+ IROW_INT(rem)
+ IROW_INT(rem_s)
+ IROW_INT(and)
+ IROW_INT(or)
+ IROW_INT(xor)
+ IROW_INT(shl)
+ IROW_INT(shr)
+ IROW_INT(sar)
+ IROW_SAME(illegal)
+ IROW_SAME(illegal)
+ IROW_PARTIAL(imm) // 0x10
+ IROW_UNTYPED(mov)
+ IROW_TYPED(load)
+ IROW_TYPED(store)
+ IROW_UNTYPED(copy)
+ IROW_UNTYPED(fill)
+ IROW_UNTYPED(reg_get)
+ IROW_UNTYPED(reg_set)
+ IROW_UNTYPED(idx_arr)
+ IROW_PARTIAL(lt)
+ IROW_PARTIAL(lt_s)
+ IROW_PARTIAL(le)
+ IROW_PARTIAL(le_s)
+ IROW_PARTIAL(eq)
+ IROW_PARTIAL(ge)
+ IROW_PARTIAL(ge_s)
+ IROW_PARTIAL(gt) // 0x20
+ IROW_PARTIAL(gt_s)
+ IROW_PARTIAL(ne)
+ IROW_UNTYPED(param)
+ IROW_UNTYPED(return)
+ IROW_UNTYPED(call)
+ IROW_UNTYPED(calli)
+ IROW_UNTYPED(br)
+ IROW_UNTYPED(br_z)
+ IROW_UNTYPED(br_nz)
+ IROW_UNTYPED(bri)
+ IROW_UNTYPED(bri_z)
+ IROW_UNTYPED(bri_nz)
+ IROW_INT(clz)
+ IROW_INT(ctz)
+ IROW_INT(popcount)
+ IROW_INT(rotl) // 0x30
+ IROW_INT(rotr)
+ IROW_FLOAT(abs)
+ IROW_FLOAT(neg)
+ IROW_FLOAT(ceil)
+ IROW_FLOAT(floor)
+ IROW_FLOAT(trunc)
+ IROW_FLOAT(nearest)
+ IROW_FLOAT(sqrt)
+ IROW_FLOAT(min)
+ IROW_FLOAT(max)
+ IROW_FLOAT(copysign)
+ IROW_SAME(cvt)
+ IROW_SAME(cvt)
+ IROW_SAME(cvt)
+ IROW_SAME(cvt)
+ IROW_SAME(cvt) // 0x40
+ IROW_SAME(cvt)
+ IROW_SAME(cvt)
+ IROW_SAME(cvt)
+ IROW_SAME(cvt)
+ IROW_SAME(cvt)
+ IROW_SAME(cvt)
+ IROW_SAME(cvt)
+ IROW_SAME(cvt)
+ IROW_SAME(cvt)
+ IROW_SAME(cvt)
+ IROW_SAME(cvt)
+ IROW_INT(cmpxchg)
+ IROW_SAME(illegal)
};