updated interpreter callbacks to use inline registration like constantpropagationpass

This commit is contained in:
Anthony Pesch 2015-07-22 01:26:19 -07:00
parent a2691d1e5b
commit f7049e7166
4 changed files with 365 additions and 405 deletions

View File

@ -8,9 +8,120 @@ using namespace dreavm::cpu::backend::interpreter;
using namespace dreavm::cpu::ir;
using namespace dreavm::emu;
// callbacks for each IR operation. callback functions are generated per
// operation, per signature, per access mask.
#define MAX_CALLBACKS_PER_OP \
(VALUE_NUM * VALUE_NUM * VALUE_NUM * NUM_ACC_COMBINATIONS)
#define MAX_CALLBACKS (MAX_CALLBACKS_PER_OP * NUM_OPCODES)
static IntFn int_cbs[MAX_CALLBACKS];
// OP_SELECT and OP_BRANCH_COND are the only instructions using arg2, and
// arg2's type always matches arg1's. because of this, arg2 isn't considered
// when generating the lookup table.
#define CALLBACK_IDX(op, result_sig, arg0_sig, arg1_sig, access_mask) \
(MAX_CALLBACKS_PER_OP * op + (((result_sig * VALUE_NUM * VALUE_NUM) + \
(arg0_sig * VALUE_NUM) + arg1_sig) * \
NUM_ACC_COMBINATIONS) + \
access_mask)
// declare a templated callback for an IR operation. note, declaring a
// callback does not actually register it. callbacks must be registered
// for a particular signature with REGISTER_CALLBACK.
#define CALLBACK(name) \
template <typename R = void, typename A0 = void, typename A1 = void, \
int ACCESS_MASK = 0> \
static uint32_t name(const IntInstr *i, uint32_t idx, Memory *memory, \
IntValue *r, uint8_t *locals, void *guest_ctx)
// generate NUM_ACC_COMBINATIONS callbacks for each operation, excluding access
// masks where (mask & 0x3), (mask >> 2) & 0x3, or (mask >> 4) & 0x3 are equal
// to 3, as they're not valid access masks
// FIXME if ConstantPropagationPass is working 100%, more of these combinations
// can be removed
#define REGISTER_CALLBACK_C(op, fn, r, a0, a1, c) \
int_cbs[CALLBACK_IDX(OP_##op, VALUE_##r, VALUE_##a0, VALUE_##a1, c)] = \
&fn<ValueType<VALUE_##r>::type, ValueType<VALUE_##a0>::type, \
ValueType<VALUE_##a1>::type, c>;
#define REGISTER_CALLBACK(op, fn, r, a0, a1) \
static struct _int_##op##_##r##_##a0##_##a1##_init { \
_int_##op##_##r##_##a0##_##a1##_init() { \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 0) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 1) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 2) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 4) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 5) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 6) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 8) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 9) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 10) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 16) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 17) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 18) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 20) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 21) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 22) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 24) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 25) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 26) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 32) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 33) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 34) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 36) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 37) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 38) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 40) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 41) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 42) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 64) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 65) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 66) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 68) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 69) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 70) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 72) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 73) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 74) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 80) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 81) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 82) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 84) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 85) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 86) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 88) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 89) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 90) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 96) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 97) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 98) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 100) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 101) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 102) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 104) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 105) \
REGISTER_CALLBACK_C(op, fn, r, a0, a1, 106) \
} \
} int_##op##_##r##_##a0##_##a1##_init
IntFn dreavm::cpu::backend::interpreter::GetCallback(
Opcode op, const IntSig &sig, IntAccessMask access_mask) {
IntFn fn =
int_cbs[CALLBACK_IDX(op, GetArgSignature(sig, 3), GetArgSignature(sig, 0),
GetArgSignature(sig, 1), access_mask)];
CHECK_NOTNULL(fn);
return fn;
}
//
// helpers for loading / storing arguments
//
#define LOAD_ARG0() helper<A0, 0, ACCESS_MASK>::LoadArg(i, r, locals)
#define LOAD_ARG1() helper<A1, 1, ACCESS_MASK>::LoadArg(i, r, locals)
#define LOAD_ARG2() helper<A1, 2, ACCESS_MASK>::LoadArg(i, r, locals)
#define STORE_RESULT(v) helper<R, 3, ACCESS_MASK>::StoreArg(i, r, locals, v)
#define NEXT_INSTR (idx + 1)
template <typename T>
static inline T GetValue(const IntValue &v);
template <>
@ -127,11 +238,8 @@ struct helper {
const uint8_t *l, T v);
};
//
// ACC_REG
//
// argument is located in a virtual register, arg->i32 specifies the register
//
template <typename T, int ARG, IntAccessMask ACCESS_MASK>
struct helper<
T, ARG, ACCESS_MASK,
@ -146,11 +254,8 @@ struct helper<
}
};
//
// ACC_LCL
//
// argument is located on the stack, arg->i32 specifies the stack offset
//
template <typename T, int ARG, IntAccessMask ACCESS_MASK>
struct helper<
T, ARG, ACCESS_MASK,
@ -165,11 +270,8 @@ struct helper<
}
};
//
// ACC_IMM
//
// argument is encoded directly on the instruction
//
template <typename T, int ARG, IntAccessMask ACCESS_MASK>
struct helper<
T, ARG, ACCESS_MASK,
@ -184,17 +286,6 @@ struct helper<
}
};
#define CALLBACK(name) \
template <typename R = void, typename A0 = void, typename A1 = void, \
int ACCESS_MASK = 0> \
static uint32_t name(const IntInstr *i, uint32_t idx, Memory *memory, \
IntValue *r, uint8_t *locals, void *guest_ctx)
#define LOAD_ARG0() helper<A0, 0, ACCESS_MASK>::LoadArg(i, r, locals)
#define LOAD_ARG1() helper<A1, 1, ACCESS_MASK>::LoadArg(i, r, locals)
#define LOAD_ARG2() helper<A1, 2, ACCESS_MASK>::LoadArg(i, r, locals)
#define STORE_RESULT(v) helper<R, 3, ACCESS_MASK>::StoreArg(i, r, locals, v)
#define NEXT_INSTR (idx + 1)
//
// interpreter callbacks
//
@ -202,6 +293,12 @@ CALLBACK(PRINTF) {
std::cout << LOAD_ARG0() << std::endl;
return NEXT_INSTR;
}
REGISTER_CALLBACK(PRINTF, PRINTF, V, I8, V);
REGISTER_CALLBACK(PRINTF, PRINTF, V, I16, V);
REGISTER_CALLBACK(PRINTF, PRINTF, V, I32, V);
REGISTER_CALLBACK(PRINTF, PRINTF, V, I64, V);
REGISTER_CALLBACK(PRINTF, PRINTF, V, F32, V);
REGISTER_CALLBACK(PRINTF, PRINTF, V, F64, V);
CALLBACK(LOAD_CONTEXT) {
A0 offset = LOAD_ARG0();
@ -209,6 +306,12 @@ CALLBACK(LOAD_CONTEXT) {
STORE_RESULT(v);
return NEXT_INSTR;
}
REGISTER_CALLBACK(LOAD_CONTEXT, LOAD_CONTEXT, I8, I32, V);
REGISTER_CALLBACK(LOAD_CONTEXT, LOAD_CONTEXT, I16, I32, V);
REGISTER_CALLBACK(LOAD_CONTEXT, LOAD_CONTEXT, I32, I32, V);
REGISTER_CALLBACK(LOAD_CONTEXT, LOAD_CONTEXT, I64, I32, V);
REGISTER_CALLBACK(LOAD_CONTEXT, LOAD_CONTEXT, F32, I32, V);
REGISTER_CALLBACK(LOAD_CONTEXT, LOAD_CONTEXT, F64, I32, V);
CALLBACK(STORE_CONTEXT) {
A0 offset = LOAD_ARG0();
@ -216,6 +319,12 @@ CALLBACK(STORE_CONTEXT) {
*reinterpret_cast<A1 *>(reinterpret_cast<uint8_t *>(guest_ctx) + offset) = v;
return NEXT_INSTR;
}
REGISTER_CALLBACK(STORE_CONTEXT, STORE_CONTEXT, V, I32, I8);
REGISTER_CALLBACK(STORE_CONTEXT, STORE_CONTEXT, V, I32, I16);
REGISTER_CALLBACK(STORE_CONTEXT, STORE_CONTEXT, V, I32, I32);
REGISTER_CALLBACK(STORE_CONTEXT, STORE_CONTEXT, V, I32, I64);
REGISTER_CALLBACK(STORE_CONTEXT, STORE_CONTEXT, V, I32, F32);
REGISTER_CALLBACK(STORE_CONTEXT, STORE_CONTEXT, V, I32, F64);
CALLBACK(LOAD_I8) {
uint32_t addr = (uint32_t)LOAD_ARG0();
@ -223,41 +332,42 @@ CALLBACK(LOAD_I8) {
STORE_RESULT(v);
return NEXT_INSTR;
}
CALLBACK(LOAD_I16) {
uint32_t addr = (uint32_t)LOAD_ARG0();
R v = memory->R16(addr);
STORE_RESULT(v);
return NEXT_INSTR;
}
CALLBACK(LOAD_I32) {
uint32_t addr = (uint32_t)LOAD_ARG0();
R v = memory->R32(addr);
STORE_RESULT(v);
return NEXT_INSTR;
}
CALLBACK(LOAD_I64) {
uint32_t addr = (uint32_t)LOAD_ARG0();
R v = memory->R64(addr);
STORE_RESULT(v);
return NEXT_INSTR;
}
CALLBACK(LOAD_F32) {
uint32_t addr = (uint32_t)LOAD_ARG0();
R v = memory->RF32(addr);
STORE_RESULT(v);
return NEXT_INSTR;
}
CALLBACK(LOAD_F64) {
uint32_t addr = (uint32_t)LOAD_ARG0();
R v = memory->RF64(addr);
STORE_RESULT(v);
return NEXT_INSTR;
}
REGISTER_CALLBACK(LOAD, LOAD_I8, I8, I32, V);
REGISTER_CALLBACK(LOAD, LOAD_I16, I16, I32, V);
REGISTER_CALLBACK(LOAD, LOAD_I32, I32, I32, V);
REGISTER_CALLBACK(LOAD, LOAD_I64, I64, I32, V);
REGISTER_CALLBACK(LOAD, LOAD_F32, F32, I32, V);
REGISTER_CALLBACK(LOAD, LOAD_F64, F64, I32, V);
CALLBACK(STORE_I8) {
uint32_t addr = (uint32_t)LOAD_ARG0();
@ -265,53 +375,65 @@ CALLBACK(STORE_I8) {
memory->W8(addr, v);
return NEXT_INSTR;
}
CALLBACK(STORE_I16) {
uint32_t addr = (uint32_t)LOAD_ARG0();
A1 v = LOAD_ARG1();
memory->W16(addr, v);
return NEXT_INSTR;
}
CALLBACK(STORE_I32) {
uint32_t addr = (uint32_t)LOAD_ARG0();
A1 v = LOAD_ARG1();
memory->W32(addr, v);
return NEXT_INSTR;
}
CALLBACK(STORE_I64) {
uint32_t addr = (uint32_t)LOAD_ARG0();
A1 v = LOAD_ARG1();
memory->W64(addr, v);
return NEXT_INSTR;
}
CALLBACK(STORE_F32) {
uint32_t addr = (uint32_t)LOAD_ARG0();
A1 v = LOAD_ARG1();
memory->WF32(addr, v);
return NEXT_INSTR;
}
CALLBACK(STORE_F64) {
uint32_t addr = (uint32_t)LOAD_ARG0();
A1 v = LOAD_ARG1();
memory->WF64(addr, v);
return NEXT_INSTR;
}
REGISTER_CALLBACK(STORE, STORE_I8, V, I32, I8);
REGISTER_CALLBACK(STORE, STORE_I16, V, I32, I16);
REGISTER_CALLBACK(STORE, STORE_I32, V, I32, I32);
REGISTER_CALLBACK(STORE, STORE_I64, V, I32, I64);
REGISTER_CALLBACK(STORE, STORE_F32, V, I32, F32);
REGISTER_CALLBACK(STORE, STORE_F64, V, I32, F64);
CALLBACK(CAST) {
A0 v = LOAD_ARG0();
STORE_RESULT((R)v);
return NEXT_INSTR;
}
REGISTER_CALLBACK(CAST, CAST, F32, I32, V);
REGISTER_CALLBACK(CAST, CAST, F64, I32, V);
REGISTER_CALLBACK(CAST, CAST, F64, I64, V);
REGISTER_CALLBACK(CAST, CAST, I32, F32, V);
REGISTER_CALLBACK(CAST, CAST, I64, F64, V);
CALLBACK(SEXT) {
A0 v = LOAD_ARG0();
STORE_RESULT((R)v);
return NEXT_INSTR;
}
REGISTER_CALLBACK(SEXT, SEXT, I16, I8, V);
REGISTER_CALLBACK(SEXT, SEXT, I32, I8, V);
REGISTER_CALLBACK(SEXT, SEXT, I64, I8, V);
REGISTER_CALLBACK(SEXT, SEXT, I32, I16, V);
REGISTER_CALLBACK(SEXT, SEXT, I64, I16, V);
REGISTER_CALLBACK(SEXT, SEXT, I64, I32, V);
CALLBACK(ZEXT) {
using U0 = typename std::make_unsigned<A0>::type;
@ -319,6 +441,12 @@ CALLBACK(ZEXT) {
STORE_RESULT((R)(U0)v);
return NEXT_INSTR;
}
REGISTER_CALLBACK(ZEXT, ZEXT, I16, I8, V);
REGISTER_CALLBACK(ZEXT, ZEXT, I32, I8, V);
REGISTER_CALLBACK(ZEXT, ZEXT, I64, I8, V);
REGISTER_CALLBACK(ZEXT, ZEXT, I32, I16, V);
REGISTER_CALLBACK(ZEXT, ZEXT, I64, I16, V);
REGISTER_CALLBACK(ZEXT, ZEXT, I64, I32, V);
CALLBACK(TRUNCATE) {
using U0 = typename std::make_unsigned<A0>::type;
@ -326,6 +454,12 @@ CALLBACK(TRUNCATE) {
STORE_RESULT((R)(U0)v);
return NEXT_INSTR;
}
REGISTER_CALLBACK(TRUNCATE, TRUNCATE, I8, I16, V);
REGISTER_CALLBACK(TRUNCATE, TRUNCATE, I8, I32, V);
REGISTER_CALLBACK(TRUNCATE, TRUNCATE, I16, I32, V);
REGISTER_CALLBACK(TRUNCATE, TRUNCATE, I8, I64, V);
REGISTER_CALLBACK(TRUNCATE, TRUNCATE, I16, I64, V);
REGISTER_CALLBACK(TRUNCATE, TRUNCATE, I32, I64, V);
CALLBACK(SELECT) {
A0 cond = LOAD_ARG0();
@ -334,6 +468,10 @@ CALLBACK(SELECT) {
STORE_RESULT(cond ? t : f);
return NEXT_INSTR;
}
REGISTER_CALLBACK(SELECT, SELECT, I8, I8, I8);
REGISTER_CALLBACK(SELECT, SELECT, I16, I8, I16);
REGISTER_CALLBACK(SELECT, SELECT, I32, I8, I32);
REGISTER_CALLBACK(SELECT, SELECT, I64, I8, I64);
CALLBACK(EQ) {
A0 lhs = LOAD_ARG0();
@ -341,6 +479,12 @@ CALLBACK(EQ) {
STORE_RESULT((int8_t)(lhs == rhs));
return NEXT_INSTR;
}
REGISTER_CALLBACK(EQ, EQ, I8, I8, I8);
REGISTER_CALLBACK(EQ, EQ, I8, I16, I16);
REGISTER_CALLBACK(EQ, EQ, I8, I32, I32);
REGISTER_CALLBACK(EQ, EQ, I8, I64, I64);
REGISTER_CALLBACK(EQ, EQ, I8, F32, F32);
REGISTER_CALLBACK(EQ, EQ, I8, F64, F64);
CALLBACK(NE) {
A0 lhs = LOAD_ARG0();
@ -348,6 +492,12 @@ CALLBACK(NE) {
STORE_RESULT((int8_t)(lhs != rhs));
return NEXT_INSTR;
}
REGISTER_CALLBACK(NE, NE, I8, I8, I8);
REGISTER_CALLBACK(NE, NE, I8, I16, I16);
REGISTER_CALLBACK(NE, NE, I8, I32, I32);
REGISTER_CALLBACK(NE, NE, I8, I64, I64);
REGISTER_CALLBACK(NE, NE, I8, F32, F32);
REGISTER_CALLBACK(NE, NE, I8, F64, F64);
CALLBACK(SGE) {
A0 lhs = LOAD_ARG0();
@ -355,6 +505,12 @@ CALLBACK(SGE) {
STORE_RESULT((int8_t)(lhs >= rhs));
return NEXT_INSTR;
}
REGISTER_CALLBACK(SGE, SGE, I8, I8, I8);
REGISTER_CALLBACK(SGE, SGE, I8, I16, I16);
REGISTER_CALLBACK(SGE, SGE, I8, I32, I32);
REGISTER_CALLBACK(SGE, SGE, I8, I64, I64);
REGISTER_CALLBACK(SGE, SGE, I8, F32, F32);
REGISTER_CALLBACK(SGE, SGE, I8, F64, F64);
CALLBACK(SGT) {
A0 lhs = LOAD_ARG0();
@ -362,6 +518,12 @@ CALLBACK(SGT) {
STORE_RESULT((int8_t)(lhs > rhs));
return NEXT_INSTR;
}
REGISTER_CALLBACK(SGT, SGT, I8, I8, I8);
REGISTER_CALLBACK(SGT, SGT, I8, I16, I16);
REGISTER_CALLBACK(SGT, SGT, I8, I32, I32);
REGISTER_CALLBACK(SGT, SGT, I8, I64, I64);
REGISTER_CALLBACK(SGT, SGT, I8, F32, F32);
REGISTER_CALLBACK(SGT, SGT, I8, F64, F64);
CALLBACK(UGE) {
using U0 = typename std::make_unsigned<A0>::type;
@ -371,6 +533,10 @@ CALLBACK(UGE) {
STORE_RESULT((int8_t)(lhs >= rhs));
return NEXT_INSTR;
}
REGISTER_CALLBACK(UGE, UGE, I8, I8, I8);
REGISTER_CALLBACK(UGE, UGE, I8, I16, I16);
REGISTER_CALLBACK(UGE, UGE, I8, I32, I32);
REGISTER_CALLBACK(UGE, UGE, I8, I64, I64);
CALLBACK(UGT) {
using U0 = typename std::make_unsigned<A0>::type;
@ -380,6 +546,10 @@ CALLBACK(UGT) {
STORE_RESULT((int8_t)(lhs > rhs));
return NEXT_INSTR;
}
REGISTER_CALLBACK(UGT, UGT, I8, I8, I8);
REGISTER_CALLBACK(UGT, UGT, I8, I16, I16);
REGISTER_CALLBACK(UGT, UGT, I8, I32, I32);
REGISTER_CALLBACK(UGT, UGT, I8, I64, I64);
CALLBACK(SLE) {
A0 lhs = LOAD_ARG0();
@ -387,6 +557,12 @@ CALLBACK(SLE) {
STORE_RESULT((int8_t)(lhs <= rhs));
return NEXT_INSTR;
}
REGISTER_CALLBACK(SLE, SLE, I8, I8, I8);
REGISTER_CALLBACK(SLE, SLE, I8, I16, I16);
REGISTER_CALLBACK(SLE, SLE, I8, I32, I32);
REGISTER_CALLBACK(SLE, SLE, I8, I64, I64);
REGISTER_CALLBACK(SLE, SLE, I8, F32, F32);
REGISTER_CALLBACK(SLE, SLE, I8, F64, F64);
CALLBACK(SLT) {
A0 lhs = LOAD_ARG0();
@ -394,6 +570,12 @@ CALLBACK(SLT) {
STORE_RESULT((int8_t)(lhs < rhs));
return NEXT_INSTR;
}
REGISTER_CALLBACK(SLT, SLT, I8, I8, I8);
REGISTER_CALLBACK(SLT, SLT, I8, I16, I16);
REGISTER_CALLBACK(SLT, SLT, I8, I32, I32);
REGISTER_CALLBACK(SLT, SLT, I8, I64, I64);
REGISTER_CALLBACK(SLT, SLT, I8, F32, F32);
REGISTER_CALLBACK(SLT, SLT, I8, F64, F64);
CALLBACK(ULE) {
using U0 = typename std::make_unsigned<A0>::type;
@ -403,6 +585,10 @@ CALLBACK(ULE) {
STORE_RESULT((int8_t)(lhs <= rhs));
return NEXT_INSTR;
}
REGISTER_CALLBACK(ULE, ULE, I8, I8, I8);
REGISTER_CALLBACK(ULE, ULE, I8, I16, I16);
REGISTER_CALLBACK(ULE, ULE, I8, I32, I32);
REGISTER_CALLBACK(ULE, ULE, I8, I64, I64);
CALLBACK(ULT) {
using U0 = typename std::make_unsigned<A0>::type;
@ -412,6 +598,10 @@ CALLBACK(ULT) {
STORE_RESULT((int8_t)(lhs < rhs));
return NEXT_INSTR;
}
REGISTER_CALLBACK(ULT, ULT, I8, I8, I8);
REGISTER_CALLBACK(ULT, ULT, I8, I16, I16);
REGISTER_CALLBACK(ULT, ULT, I8, I32, I32);
REGISTER_CALLBACK(ULT, ULT, I8, I64, I64);
CALLBACK(ADD) {
A0 lhs = LOAD_ARG0();
@ -419,6 +609,12 @@ CALLBACK(ADD) {
STORE_RESULT(lhs + rhs);
return NEXT_INSTR;
}
REGISTER_CALLBACK(ADD, ADD, I8, I8, I8);
REGISTER_CALLBACK(ADD, ADD, I16, I16, I16);
REGISTER_CALLBACK(ADD, ADD, I32, I32, I32);
REGISTER_CALLBACK(ADD, ADD, I64, I64, I64);
REGISTER_CALLBACK(ADD, ADD, F32, F32, F32);
REGISTER_CALLBACK(ADD, ADD, F64, F64, F64);
CALLBACK(SUB) {
A0 lhs = LOAD_ARG0();
@ -426,6 +622,12 @@ CALLBACK(SUB) {
STORE_RESULT(lhs - rhs);
return NEXT_INSTR;
}
REGISTER_CALLBACK(SUB, SUB, I8, I8, I8);
REGISTER_CALLBACK(SUB, SUB, I16, I16, I16);
REGISTER_CALLBACK(SUB, SUB, I32, I32, I32);
REGISTER_CALLBACK(SUB, SUB, I64, I64, I64);
REGISTER_CALLBACK(SUB, SUB, F32, F32, F32);
REGISTER_CALLBACK(SUB, SUB, F64, F64, F64);
CALLBACK(SMUL) {
A0 lhs = LOAD_ARG0();
@ -433,6 +635,12 @@ CALLBACK(SMUL) {
STORE_RESULT(lhs * rhs);
return NEXT_INSTR;
}
REGISTER_CALLBACK(SMUL, SMUL, I8, I8, I8);
REGISTER_CALLBACK(SMUL, SMUL, I16, I16, I16);
REGISTER_CALLBACK(SMUL, SMUL, I32, I32, I32);
REGISTER_CALLBACK(SMUL, SMUL, I64, I64, I64);
REGISTER_CALLBACK(SMUL, SMUL, F32, F32, F32);
REGISTER_CALLBACK(SMUL, SMUL, F64, F64, F64);
CALLBACK(UMUL) {
using U0 = typename std::make_unsigned<A0>::type;
@ -442,6 +650,10 @@ CALLBACK(UMUL) {
STORE_RESULT((A0)(lhs * rhs));
return NEXT_INSTR;
}
REGISTER_CALLBACK(UMUL, UMUL, I8, I8, I8);
REGISTER_CALLBACK(UMUL, UMUL, I16, I16, I16);
REGISTER_CALLBACK(UMUL, UMUL, I32, I32, I32);
REGISTER_CALLBACK(UMUL, UMUL, I64, I64, I64);
CALLBACK(DIV) {
A0 lhs = LOAD_ARG0();
@ -449,54 +661,71 @@ CALLBACK(DIV) {
STORE_RESULT(lhs / rhs);
return NEXT_INSTR;
}
REGISTER_CALLBACK(DIV, DIV, I8, I8, I8);
REGISTER_CALLBACK(DIV, DIV, I16, I16, I16);
REGISTER_CALLBACK(DIV, DIV, I32, I32, I32);
REGISTER_CALLBACK(DIV, DIV, I64, I64, I64);
REGISTER_CALLBACK(DIV, DIV, F32, F32, F32);
REGISTER_CALLBACK(DIV, DIV, F64, F64, F64);
CALLBACK(NEG) {
A0 v = LOAD_ARG0();
STORE_RESULT(-v);
return NEXT_INSTR;
}
REGISTER_CALLBACK(NEG, NEG, I8, I8, V);
REGISTER_CALLBACK(NEG, NEG, I16, I16, V);
REGISTER_CALLBACK(NEG, NEG, I32, I32, V);
REGISTER_CALLBACK(NEG, NEG, I64, I64, V);
REGISTER_CALLBACK(NEG, NEG, F32, F32, V);
REGISTER_CALLBACK(NEG, NEG, F64, F64, V);
CALLBACK(SQRTF) {
A0 v = LOAD_ARG0();
STORE_RESULT(sqrtf(v));
return NEXT_INSTR;
}
CALLBACK(SQRT) {
A0 v = LOAD_ARG0();
STORE_RESULT(sqrt(v));
return NEXT_INSTR;
}
REGISTER_CALLBACK(SQRT, SQRTF, F32, F32, V);
REGISTER_CALLBACK(SQRT, SQRT, F64, F64, V);
CALLBACK(ABSF) {
A0 v = LOAD_ARG0();
STORE_RESULT(fabs(v));
return NEXT_INSTR;
}
REGISTER_CALLBACK(ABS, ABSF, F32, F32, V);
REGISTER_CALLBACK(ABS, ABSF, F64, F64, V);
CALLBACK(SINF) {
A0 v = LOAD_ARG0();
STORE_RESULT(sinf(v));
return NEXT_INSTR;
}
CALLBACK(SIN) {
A0 v = LOAD_ARG0();
STORE_RESULT(sin(v));
return NEXT_INSTR;
}
REGISTER_CALLBACK(SIN, SINF, F32, F32, V);
REGISTER_CALLBACK(SIN, SIN, F64, F64, V);
CALLBACK(COSF) {
A0 v = LOAD_ARG0();
STORE_RESULT(cosf(v));
return NEXT_INSTR;
}
CALLBACK(COS) {
A0 v = LOAD_ARG0();
STORE_RESULT(cos(v));
return NEXT_INSTR;
}
REGISTER_CALLBACK(COS, COSF, F32, F32, V);
REGISTER_CALLBACK(COS, COS, F64, F64, V);
CALLBACK(AND) {
A0 lhs = LOAD_ARG0();
@ -504,6 +733,10 @@ CALLBACK(AND) {
STORE_RESULT(lhs & rhs);
return NEXT_INSTR;
}
REGISTER_CALLBACK(AND, AND, I8, I8, I8);
REGISTER_CALLBACK(AND, AND, I16, I16, I16);
REGISTER_CALLBACK(AND, AND, I32, I32, I32);
REGISTER_CALLBACK(AND, AND, I64, I64, I64);
CALLBACK(OR) {
A0 lhs = LOAD_ARG0();
@ -511,6 +744,10 @@ CALLBACK(OR) {
STORE_RESULT(lhs | rhs);
return NEXT_INSTR;
}
REGISTER_CALLBACK(OR, OR, I8, I8, I8);
REGISTER_CALLBACK(OR, OR, I16, I16, I16);
REGISTER_CALLBACK(OR, OR, I32, I32, I32);
REGISTER_CALLBACK(OR, OR, I64, I64, I64);
CALLBACK(XOR) {
A0 lhs = LOAD_ARG0();
@ -518,12 +755,20 @@ CALLBACK(XOR) {
STORE_RESULT(lhs ^ rhs);
return NEXT_INSTR;
}
REGISTER_CALLBACK(XOR, XOR, I8, I8, I8);
REGISTER_CALLBACK(XOR, XOR, I16, I16, I16);
REGISTER_CALLBACK(XOR, XOR, I32, I32, I32);
REGISTER_CALLBACK(XOR, XOR, I64, I64, I64);
CALLBACK(NOT) {
A0 v = LOAD_ARG0();
STORE_RESULT(~v);
return NEXT_INSTR;
}
REGISTER_CALLBACK(NOT, NOT, I8, I8, V);
REGISTER_CALLBACK(NOT, NOT, I16, I16, V);
REGISTER_CALLBACK(NOT, NOT, I32, I32, V);
REGISTER_CALLBACK(NOT, NOT, I64, I64, V);
CALLBACK(SHL) {
A0 v = LOAD_ARG0();
@ -531,6 +776,10 @@ CALLBACK(SHL) {
STORE_RESULT(v << n);
return NEXT_INSTR;
}
REGISTER_CALLBACK(SHL, SHL, I8, I8, I32);
REGISTER_CALLBACK(SHL, SHL, I16, I16, I32);
REGISTER_CALLBACK(SHL, SHL, I32, I32, I32);
REGISTER_CALLBACK(SHL, SHL, I64, I64, I32);
CALLBACK(ASHR) {
A0 v = LOAD_ARG0();
@ -538,6 +787,10 @@ CALLBACK(ASHR) {
STORE_RESULT(v >> n);
return NEXT_INSTR;
}
REGISTER_CALLBACK(ASHR, ASHR, I8, I8, I32);
REGISTER_CALLBACK(ASHR, ASHR, I16, I16, I32);
REGISTER_CALLBACK(ASHR, ASHR, I32, I32, I32);
REGISTER_CALLBACK(ASHR, ASHR, I64, I64, I32);
CALLBACK(LSHR) {
using U0 = typename std::make_unsigned<A0>::type;
@ -546,12 +799,20 @@ CALLBACK(LSHR) {
STORE_RESULT((A0)((U0)v >> n));
return NEXT_INSTR;
}
REGISTER_CALLBACK(LSHR, LSHR, I8, I8, I32);
REGISTER_CALLBACK(LSHR, LSHR, I16, I16, I32);
REGISTER_CALLBACK(LSHR, LSHR, I32, I32, I32);
REGISTER_CALLBACK(LSHR, LSHR, I64, I64, I32);
CALLBACK(BRANCH) {
using U0 = typename std::make_unsigned<A0>::type;
U0 addr = (U0)LOAD_ARG0();
return addr;
}
REGISTER_CALLBACK(BRANCH, BRANCH, V, I8, V);
REGISTER_CALLBACK(BRANCH, BRANCH, V, I16, V);
REGISTER_CALLBACK(BRANCH, BRANCH, V, I32, V);
REGISTER_CALLBACK(BRANCH, BRANCH, V, I64, V);
CALLBACK(BRANCH_COND) {
using U1 = typename std::make_unsigned<A1>::type;
@ -564,11 +825,16 @@ CALLBACK(BRANCH_COND) {
return addr;
}
}
REGISTER_CALLBACK(BRANCH_COND, BRANCH_COND, V, I8, I8);
REGISTER_CALLBACK(BRANCH_COND, BRANCH_COND, V, I8, I16);
REGISTER_CALLBACK(BRANCH_COND, BRANCH_COND, V, I8, I32);
REGISTER_CALLBACK(BRANCH_COND, BRANCH_COND, V, I8, I64);
CALLBACK(BRANCH_INDIRECT) {
uint32_t addr = (uint32_t)LOAD_ARG0();
return addr;
}
REGISTER_CALLBACK(BRANCH_INDIRECT, BRANCH_INDIRECT, V, I32, V);
CALLBACK(CALL_EXTERNAL) {
A0 addr = LOAD_ARG0();
@ -576,105 +842,4 @@ CALLBACK(CALL_EXTERNAL) {
func(guest_ctx);
return NEXT_INSTR;
}
//
// callback lookup table generation
//
// callback functions are generated for each instruction, for each possible
// permutation of arguments. each argument has a data type, as well as its
// access type.
//
// NOTE: OP_SELECT and OP_BRANCH_COND are the only instructions using arg2, and
// arg2's type always matches arg1's. because of this, and in order to save
// some memory, arg2 isn't considering when generating the lookup table.
//
#define MAX_CALLBACKS_PER_OP \
(VALUE_NUM * VALUE_NUM * VALUE_NUM * NUM_ACC_COMBINATIONS)
#define MAX_CALLBACKS (MAX_CALLBACKS_PER_OP * NUM_OPCODES)
#define CALLBACK_IDX(op, result_sig, arg0_sig, arg1_sig, access_mask) \
(MAX_CALLBACKS_PER_OP * op + (((result_sig * VALUE_NUM * VALUE_NUM) + \
(arg0_sig * VALUE_NUM) + arg1_sig) * \
NUM_ACC_COMBINATIONS) + \
access_mask)
static IntFn int_cbs[MAX_CALLBACKS];
IntFn dreavm::cpu::backend::interpreter::GetCallback(
Opcode op, const IntSig &sig, IntAccessMask access_mask) {
IntFn fn =
int_cbs[CALLBACK_IDX(op, GetArgSignature(sig, 3), GetArgSignature(sig, 0),
GetArgSignature(sig, 1), access_mask)];
CHECK_NOTNULL(fn);
return fn;
}
static void InitCallbacks() {
// Generate NUM_ACC_COMBINATIONS callbacks for each op, excluding access masks
// where (mask & 0x3), (mask >> 2) & 0x3, or (mask >> 4) & 0x3 are equal to 3,
// as they're invalid.
#define INT_CALLBACK_C(op, func, r, a0, a1, c) \
int_cbs[CALLBACK_IDX(op, VALUE_##r, VALUE_##a0, VALUE_##a1, c)] = \
&func<ValueType<VALUE_##r>::type, ValueType<VALUE_##a0>::type, \
ValueType<VALUE_##a1>::type, c>;
#define INT_CALLBACK(op, func, r, a0, a1) \
INT_CALLBACK_C(op, func, r, a0, a1, 0) \
INT_CALLBACK_C(op, func, r, a0, a1, 1) \
INT_CALLBACK_C(op, func, r, a0, a1, 2) \
INT_CALLBACK_C(op, func, r, a0, a1, 4) \
INT_CALLBACK_C(op, func, r, a0, a1, 5) \
INT_CALLBACK_C(op, func, r, a0, a1, 6) \
INT_CALLBACK_C(op, func, r, a0, a1, 8) \
INT_CALLBACK_C(op, func, r, a0, a1, 9) \
INT_CALLBACK_C(op, func, r, a0, a1, 10) \
INT_CALLBACK_C(op, func, r, a0, a1, 16) \
INT_CALLBACK_C(op, func, r, a0, a1, 17) \
INT_CALLBACK_C(op, func, r, a0, a1, 18) \
INT_CALLBACK_C(op, func, r, a0, a1, 20) \
INT_CALLBACK_C(op, func, r, a0, a1, 21) \
INT_CALLBACK_C(op, func, r, a0, a1, 22) \
INT_CALLBACK_C(op, func, r, a0, a1, 24) \
INT_CALLBACK_C(op, func, r, a0, a1, 25) \
INT_CALLBACK_C(op, func, r, a0, a1, 26) \
INT_CALLBACK_C(op, func, r, a0, a1, 32) \
INT_CALLBACK_C(op, func, r, a0, a1, 33) \
INT_CALLBACK_C(op, func, r, a0, a1, 34) \
INT_CALLBACK_C(op, func, r, a0, a1, 36) \
INT_CALLBACK_C(op, func, r, a0, a1, 37) \
INT_CALLBACK_C(op, func, r, a0, a1, 38) \
INT_CALLBACK_C(op, func, r, a0, a1, 40) \
INT_CALLBACK_C(op, func, r, a0, a1, 41) \
INT_CALLBACK_C(op, func, r, a0, a1, 42) \
INT_CALLBACK_C(op, func, r, a0, a1, 64) \
INT_CALLBACK_C(op, func, r, a0, a1, 65) \
INT_CALLBACK_C(op, func, r, a0, a1, 66) \
INT_CALLBACK_C(op, func, r, a0, a1, 68) \
INT_CALLBACK_C(op, func, r, a0, a1, 69) \
INT_CALLBACK_C(op, func, r, a0, a1, 70) \
INT_CALLBACK_C(op, func, r, a0, a1, 72) \
INT_CALLBACK_C(op, func, r, a0, a1, 73) \
INT_CALLBACK_C(op, func, r, a0, a1, 74) \
INT_CALLBACK_C(op, func, r, a0, a1, 80) \
INT_CALLBACK_C(op, func, r, a0, a1, 81) \
INT_CALLBACK_C(op, func, r, a0, a1, 82) \
INT_CALLBACK_C(op, func, r, a0, a1, 84) \
INT_CALLBACK_C(op, func, r, a0, a1, 85) \
INT_CALLBACK_C(op, func, r, a0, a1, 86) \
INT_CALLBACK_C(op, func, r, a0, a1, 88) \
INT_CALLBACK_C(op, func, r, a0, a1, 89) \
INT_CALLBACK_C(op, func, r, a0, a1, 90) \
INT_CALLBACK_C(op, func, r, a0, a1, 96) \
INT_CALLBACK_C(op, func, r, a0, a1, 97) \
INT_CALLBACK_C(op, func, r, a0, a1, 98) \
INT_CALLBACK_C(op, func, r, a0, a1, 100) \
INT_CALLBACK_C(op, func, r, a0, a1, 101) \
INT_CALLBACK_C(op, func, r, a0, a1, 102) \
INT_CALLBACK_C(op, func, r, a0, a1, 104) \
INT_CALLBACK_C(op, func, r, a0, a1, 105) \
INT_CALLBACK_C(op, func, r, a0, a1, 106)
#include "cpu/backend/interpreter/interpreter_callbacks.inc"
#undef INT_CALLBACK
}
static struct _cb_init {
_cb_init() { InitCallbacks(); }
} cb_init;
REGISTER_CALLBACK(CALL_EXTERNAL, CALL_EXTERNAL, V, I64, V);

View File

@ -1,189 +0,0 @@
INT_CALLBACK(OP_PRINTF, PRINTF, V, I8, V)
INT_CALLBACK(OP_PRINTF, PRINTF, V, I16, V)
INT_CALLBACK(OP_PRINTF, PRINTF, V, I32, V)
INT_CALLBACK(OP_PRINTF, PRINTF, V, I64, V)
INT_CALLBACK(OP_PRINTF, PRINTF, V, F32, V)
INT_CALLBACK(OP_PRINTF, PRINTF, V, F64, V)
INT_CALLBACK(OP_LOAD_CONTEXT, LOAD_CONTEXT, I8, I32, V)
INT_CALLBACK(OP_LOAD_CONTEXT, LOAD_CONTEXT, I16, I32, V)
INT_CALLBACK(OP_LOAD_CONTEXT, LOAD_CONTEXT, I32, I32, V)
INT_CALLBACK(OP_LOAD_CONTEXT, LOAD_CONTEXT, I64, I32, V)
INT_CALLBACK(OP_LOAD_CONTEXT, LOAD_CONTEXT, F32, I32, V)
INT_CALLBACK(OP_LOAD_CONTEXT, LOAD_CONTEXT, F64, I32, V)
INT_CALLBACK(OP_STORE_CONTEXT, STORE_CONTEXT, V, I32, I8)
INT_CALLBACK(OP_STORE_CONTEXT, STORE_CONTEXT, V, I32, I16)
INT_CALLBACK(OP_STORE_CONTEXT, STORE_CONTEXT, V, I32, I32)
INT_CALLBACK(OP_STORE_CONTEXT, STORE_CONTEXT, V, I32, I64)
INT_CALLBACK(OP_STORE_CONTEXT, STORE_CONTEXT, V, I32, F32)
INT_CALLBACK(OP_STORE_CONTEXT, STORE_CONTEXT, V, I32, F64)
INT_CALLBACK(OP_LOAD, LOAD_I8, I8, I32, V)
INT_CALLBACK(OP_LOAD, LOAD_I16, I16, I32, V)
INT_CALLBACK(OP_LOAD, LOAD_I32, I32, I32, V)
INT_CALLBACK(OP_LOAD, LOAD_I64, I64, I32, V)
INT_CALLBACK(OP_LOAD, LOAD_F32, F32, I32, V)
INT_CALLBACK(OP_LOAD, LOAD_F64, F64, I32, V)
INT_CALLBACK(OP_STORE, STORE_I8, V, I32, I8)
INT_CALLBACK(OP_STORE, STORE_I16, V, I32, I16)
INT_CALLBACK(OP_STORE, STORE_I32, V, I32, I32)
INT_CALLBACK(OP_STORE, STORE_I64, V, I32, I64)
INT_CALLBACK(OP_STORE, STORE_F32, V, I32, F32)
INT_CALLBACK(OP_STORE, STORE_F64, V, I32, F64)
INT_CALLBACK(OP_CAST, CAST, F32, I32, V)
INT_CALLBACK(OP_CAST, CAST, F64, I32, V)
INT_CALLBACK(OP_CAST, CAST, F64, I64, V)
INT_CALLBACK(OP_CAST, CAST, I32, F32, V)
INT_CALLBACK(OP_CAST, CAST, I64, F64, V)
INT_CALLBACK(OP_SEXT, SEXT, I16, I8, V)
INT_CALLBACK(OP_SEXT, SEXT, I32, I8, V)
INT_CALLBACK(OP_SEXT, SEXT, I64, I8, V)
INT_CALLBACK(OP_SEXT, SEXT, I32, I16, V)
INT_CALLBACK(OP_SEXT, SEXT, I64, I16, V)
INT_CALLBACK(OP_SEXT, SEXT, I64, I32, V)
INT_CALLBACK(OP_ZEXT, ZEXT, I16, I8, V)
INT_CALLBACK(OP_ZEXT, ZEXT, I32, I8, V)
INT_CALLBACK(OP_ZEXT, ZEXT, I64, I8, V)
INT_CALLBACK(OP_ZEXT, ZEXT, I32, I16, V)
INT_CALLBACK(OP_ZEXT, ZEXT, I64, I16, V)
INT_CALLBACK(OP_ZEXT, ZEXT, I64, I32, V)
INT_CALLBACK(OP_TRUNCATE, TRUNCATE, I8, I16, V)
INT_CALLBACK(OP_TRUNCATE, TRUNCATE, I8, I32, V)
INT_CALLBACK(OP_TRUNCATE, TRUNCATE, I16, I32, V)
INT_CALLBACK(OP_TRUNCATE, TRUNCATE, I8, I64, V)
INT_CALLBACK(OP_TRUNCATE, TRUNCATE, I16, I64, V)
INT_CALLBACK(OP_TRUNCATE, TRUNCATE, I32, I64, V)
INT_CALLBACK(OP_SELECT, SELECT, I8, I8, I8)
INT_CALLBACK(OP_SELECT, SELECT, I16, I8, I16)
INT_CALLBACK(OP_SELECT, SELECT, I32, I8, I32)
INT_CALLBACK(OP_SELECT, SELECT, I64, I8, I64)
INT_CALLBACK(OP_EQ, EQ, I8, I8, I8)
INT_CALLBACK(OP_EQ, EQ, I8, I16, I16)
INT_CALLBACK(OP_EQ, EQ, I8, I32, I32)
INT_CALLBACK(OP_EQ, EQ, I8, I64, I64)
INT_CALLBACK(OP_EQ, EQ, I8, F32, F32)
INT_CALLBACK(OP_EQ, EQ, I8, F64, F64)
INT_CALLBACK(OP_NE, NE, I8, I8, I8)
INT_CALLBACK(OP_NE, NE, I8, I16, I16)
INT_CALLBACK(OP_NE, NE, I8, I32, I32)
INT_CALLBACK(OP_NE, NE, I8, I64, I64)
INT_CALLBACK(OP_NE, NE, I8, F32, F32)
INT_CALLBACK(OP_NE, NE, I8, F64, F64)
INT_CALLBACK(OP_SGE, SGE, I8, I8, I8)
INT_CALLBACK(OP_SGE, SGE, I8, I16, I16)
INT_CALLBACK(OP_SGE, SGE, I8, I32, I32)
INT_CALLBACK(OP_SGE, SGE, I8, I64, I64)
INT_CALLBACK(OP_SGE, SGE, I8, F32, F32)
INT_CALLBACK(OP_SGE, SGE, I8, F64, F64)
INT_CALLBACK(OP_SGT, SGT, I8, I8, I8)
INT_CALLBACK(OP_SGT, SGT, I8, I16, I16)
INT_CALLBACK(OP_SGT, SGT, I8, I32, I32)
INT_CALLBACK(OP_SGT, SGT, I8, I64, I64)
INT_CALLBACK(OP_SGT, SGT, I8, F32, F32)
INT_CALLBACK(OP_SGT, SGT, I8, F64, F64)
INT_CALLBACK(OP_UGE, UGE, I8, I8, I8)
INT_CALLBACK(OP_UGE, UGE, I8, I16, I16)
INT_CALLBACK(OP_UGE, UGE, I8, I32, I32)
INT_CALLBACK(OP_UGE, UGE, I8, I64, I64)
INT_CALLBACK(OP_UGT, UGT, I8, I8, I8)
INT_CALLBACK(OP_UGT, UGT, I8, I16, I16)
INT_CALLBACK(OP_UGT, UGT, I8, I32, I32)
INT_CALLBACK(OP_UGT, UGT, I8, I64, I64)
INT_CALLBACK(OP_SLE, SLE, I8, I8, I8)
INT_CALLBACK(OP_SLE, SLE, I8, I16, I16)
INT_CALLBACK(OP_SLE, SLE, I8, I32, I32)
INT_CALLBACK(OP_SLE, SLE, I8, I64, I64)
INT_CALLBACK(OP_SLE, SLE, I8, F32, F32)
INT_CALLBACK(OP_SLE, SLE, I8, F64, F64)
INT_CALLBACK(OP_SLT, SLT, I8, I8, I8)
INT_CALLBACK(OP_SLT, SLT, I8, I16, I16)
INT_CALLBACK(OP_SLT, SLT, I8, I32, I32)
INT_CALLBACK(OP_SLT, SLT, I8, I64, I64)
INT_CALLBACK(OP_SLT, SLT, I8, F32, F32)
INT_CALLBACK(OP_SLT, SLT, I8, F64, F64)
INT_CALLBACK(OP_ULE, ULE, I8, I8, I8)
INT_CALLBACK(OP_ULE, ULE, I8, I16, I16)
INT_CALLBACK(OP_ULE, ULE, I8, I32, I32)
INT_CALLBACK(OP_ULE, ULE, I8, I64, I64)
INT_CALLBACK(OP_ULT, ULT, I8, I8, I8)
INT_CALLBACK(OP_ULT, ULT, I8, I16, I16)
INT_CALLBACK(OP_ULT, ULT, I8, I32, I32)
INT_CALLBACK(OP_ULT, ULT, I8, I64, I64)
INT_CALLBACK(OP_ADD, ADD, I8, I8, I8)
INT_CALLBACK(OP_ADD, ADD, I16, I16, I16)
INT_CALLBACK(OP_ADD, ADD, I32, I32, I32)
INT_CALLBACK(OP_ADD, ADD, I64, I64, I64)
INT_CALLBACK(OP_ADD, ADD, F32, F32, F32)
INT_CALLBACK(OP_ADD, ADD, F64, F64, F64)
INT_CALLBACK(OP_SUB, SUB, I8, I8, I8)
INT_CALLBACK(OP_SUB, SUB, I16, I16, I16)
INT_CALLBACK(OP_SUB, SUB, I32, I32, I32)
INT_CALLBACK(OP_SUB, SUB, I64, I64, I64)
INT_CALLBACK(OP_SUB, SUB, F32, F32, F32)
INT_CALLBACK(OP_SUB, SUB, F64, F64, F64)
INT_CALLBACK(OP_SMUL, SMUL, I8, I8, I8)
INT_CALLBACK(OP_SMUL, SMUL, I16, I16, I16)
INT_CALLBACK(OP_SMUL, SMUL, I32, I32, I32)
INT_CALLBACK(OP_SMUL, SMUL, I64, I64, I64)
INT_CALLBACK(OP_SMUL, SMUL, F32, F32, F32)
INT_CALLBACK(OP_SMUL, SMUL, F64, F64, F64)
INT_CALLBACK(OP_UMUL, UMUL, I8, I8, I8)
INT_CALLBACK(OP_UMUL, UMUL, I16, I16, I16)
INT_CALLBACK(OP_UMUL, UMUL, I32, I32, I32)
INT_CALLBACK(OP_UMUL, UMUL, I64, I64, I64)
INT_CALLBACK(OP_DIV, DIV, I8, I8, I8)
INT_CALLBACK(OP_DIV, DIV, I16, I16, I16)
INT_CALLBACK(OP_DIV, DIV, I32, I32, I32)
INT_CALLBACK(OP_DIV, DIV, I64, I64, I64)
INT_CALLBACK(OP_DIV, DIV, F32, F32, F32)
INT_CALLBACK(OP_DIV, DIV, F64, F64, F64)
INT_CALLBACK(OP_NEG, NEG, I8, I8, V)
INT_CALLBACK(OP_NEG, NEG, I16, I16, V)
INT_CALLBACK(OP_NEG, NEG, I32, I32, V)
INT_CALLBACK(OP_NEG, NEG, I64, I64, V)
INT_CALLBACK(OP_NEG, NEG, F32, F32, V)
INT_CALLBACK(OP_NEG, NEG, F64, F64, V)
INT_CALLBACK(OP_SQRT, SQRTF, F32, F32, V)
INT_CALLBACK(OP_SQRT, SQRT, F64, F64, V)
INT_CALLBACK(OP_ABS, ABSF, F32, F32, V)
INT_CALLBACK(OP_ABS, ABSF, F64, F64, V)
INT_CALLBACK(OP_SIN, SINF, F32, F32, V)
INT_CALLBACK(OP_SIN, SIN, F64, F64, V)
INT_CALLBACK(OP_COS, COSF, F32, F32, V)
INT_CALLBACK(OP_COS, COS, F64, F64, V)
INT_CALLBACK(OP_AND, AND, I8, I8, I8)
INT_CALLBACK(OP_AND, AND, I16, I16, I16)
INT_CALLBACK(OP_AND, AND, I32, I32, I32)
INT_CALLBACK(OP_AND, AND, I64, I64, I64)
INT_CALLBACK(OP_OR, OR, I8, I8, I8)
INT_CALLBACK(OP_OR, OR, I16, I16, I16)
INT_CALLBACK(OP_OR, OR, I32, I32, I32)
INT_CALLBACK(OP_OR, OR, I64, I64, I64)
INT_CALLBACK(OP_XOR, XOR, I8, I8, I8)
INT_CALLBACK(OP_XOR, XOR, I16, I16, I16)
INT_CALLBACK(OP_XOR, XOR, I32, I32, I32)
INT_CALLBACK(OP_XOR, XOR, I64, I64, I64)
INT_CALLBACK(OP_NOT, NOT, I8, I8, V)
INT_CALLBACK(OP_NOT, NOT, I16, I16, V)
INT_CALLBACK(OP_NOT, NOT, I32, I32, V)
INT_CALLBACK(OP_NOT, NOT, I64, I64, V)
INT_CALLBACK(OP_SHL, SHL, I8, I8, I32)
INT_CALLBACK(OP_SHL, SHL, I16, I16, I32)
INT_CALLBACK(OP_SHL, SHL, I32, I32, I32)
INT_CALLBACK(OP_SHL, SHL, I64, I64, I32)
INT_CALLBACK(OP_ASHR, ASHR, I8, I8, I32)
INT_CALLBACK(OP_ASHR, ASHR, I16, I16, I32)
INT_CALLBACK(OP_ASHR, ASHR, I32, I32, I32)
INT_CALLBACK(OP_ASHR, ASHR, I64, I64, I32)
INT_CALLBACK(OP_LSHR, LSHR, I8, I8, I32)
INT_CALLBACK(OP_LSHR, LSHR, I16, I16, I32)
INT_CALLBACK(OP_LSHR, LSHR, I32, I32, I32)
INT_CALLBACK(OP_LSHR, LSHR, I64, I64, I32)
INT_CALLBACK(OP_BRANCH, BRANCH, V, I8, V)
INT_CALLBACK(OP_BRANCH, BRANCH, V, I16, V)
INT_CALLBACK(OP_BRANCH, BRANCH, V, I32, V)
INT_CALLBACK(OP_BRANCH, BRANCH, V, I64, V)
INT_CALLBACK(OP_BRANCH_COND, BRANCH_COND, V, I8, I8)
INT_CALLBACK(OP_BRANCH_COND, BRANCH_COND, V, I8, I16)
INT_CALLBACK(OP_BRANCH_COND, BRANCH_COND, V, I8, I32)
INT_CALLBACK(OP_BRANCH_COND, BRANCH_COND, V, I8, I64)
INT_CALLBACK(OP_BRANCH_INDIRECT, BRANCH_INDIRECT, V, I32, V)
INT_CALLBACK(OP_CALL_EXTERNAL, CALL_EXTERNAL, V, I64, V)

View File

@ -21,9 +21,9 @@ int fold_masks[NUM_OPCODES];
#define CALLBACK_IDX(op, a0, a1) \
((op)*VALUE_NUM * VALUE_NUM) + ((a0)*VALUE_NUM) + (a1)
// declare a templated fold callback for an IR operation. note, declaring a
// fold callback does not actually register it. fold callbacks must be
// registered for any signature it is to be ran on.
// declare a templated callback for an IR operation. note, declaring a
// callback does not actually register it. callbacks must be registered
// for a particular signature with REGISTER_FOLD.
#define FOLD(op, mask) \
static struct _##op##_init { \
_##op##_init() { fold_masks[OP_##op] = mask; } \
@ -33,17 +33,13 @@ int fold_masks[NUM_OPCODES];
// registers a fold callback for the specified signature
#define REGISTER_FOLD(op, r, a0, a1) \
static struct _##op##_##r##_##a0##_##a1##_init { \
_##op##_##r##_##a0##_##a1##_init() { \
int idx = CALLBACK_IDX(OP_##op, VALUE_##a0, VALUE_##a1); \
CHECK(fold_cbs[idx] == nullptr) << "Registered duplicate callback for " \
<< Opnames[OP_##op] << "_" << #r << "_" \
<< #a0 << "_" << #a1; \
fold_cbs[idx] = \
static struct _cpp_##op##_##r##_##a0##_##a1##_init { \
_cpp_##op##_##r##_##a0##_##a1##_init() { \
fold_cbs[CALLBACK_IDX(OP_##op, VALUE_##a0, VALUE_##a1)] = \
&Handle##op<ValueType<VALUE_##r>::type, ValueType<VALUE_##a0>::type, \
ValueType<VALUE_##a1>::type>; \
} \
} op##_##r##_##a0##_##a1##_init;
} cpp_##op##_##r##_##a0##_##a1##_init
// common helpers for fold functions
#define ARG0() instr->arg0()->value<A0>()
@ -107,80 +103,80 @@ FOLD(SELECT, ARG0_CNST) {
instr->result()->ReplaceRefsWith(ARG0() ? instr->arg1() : instr->arg2());
block->RemoveInstr(instr);
}
REGISTER_FOLD(SELECT, I8, I8, I8)
REGISTER_FOLD(SELECT, I16, I16, I16)
REGISTER_FOLD(SELECT, I32, I32, I32)
REGISTER_FOLD(SELECT, I64, I64, I64)
REGISTER_FOLD(SELECT, I8, I8, I8);
REGISTER_FOLD(SELECT, I16, I16, I16);
REGISTER_FOLD(SELECT, I32, I32, I32);
REGISTER_FOLD(SELECT, I64, I64, I64);
FOLD(EQ, ARG0_CNST | ARG1_CNST) { RESULT(ARG0() == ARG1()); }
REGISTER_FOLD(EQ, I8, I8, I8)
REGISTER_FOLD(EQ, I8, I16, I16)
REGISTER_FOLD(EQ, I8, I32, I32)
REGISTER_FOLD(EQ, I8, I64, I64)
REGISTER_FOLD(EQ, I8, F32, F32)
REGISTER_FOLD(EQ, I8, F64, F64)
REGISTER_FOLD(EQ, I8, I8, I8);
REGISTER_FOLD(EQ, I8, I16, I16);
REGISTER_FOLD(EQ, I8, I32, I32);
REGISTER_FOLD(EQ, I8, I64, I64);
REGISTER_FOLD(EQ, I8, F32, F32);
REGISTER_FOLD(EQ, I8, F64, F64);
FOLD(NE, ARG0_CNST | ARG1_CNST) { RESULT(ARG0() != ARG1()); }
REGISTER_FOLD(NE, I8, I8, I8)
REGISTER_FOLD(NE, I8, I16, I16)
REGISTER_FOLD(NE, I8, I32, I32)
REGISTER_FOLD(NE, I8, I64, I64)
REGISTER_FOLD(NE, I8, F32, F32)
REGISTER_FOLD(NE, I8, F64, F64)
REGISTER_FOLD(NE, I8, I8, I8);
REGISTER_FOLD(NE, I8, I16, I16);
REGISTER_FOLD(NE, I8, I32, I32);
REGISTER_FOLD(NE, I8, I64, I64);
REGISTER_FOLD(NE, I8, F32, F32);
REGISTER_FOLD(NE, I8, F64, F64);
FOLD(SGE, ARG0_CNST | ARG1_CNST) { RESULT(ARG0() >= ARG1()); }
REGISTER_FOLD(SGE, I8, I8, I8)
REGISTER_FOLD(SGE, I8, I16, I16)
REGISTER_FOLD(SGE, I8, I32, I32)
REGISTER_FOLD(SGE, I8, I64, I64)
REGISTER_FOLD(SGE, I8, F32, F32)
REGISTER_FOLD(SGE, I8, F64, F64)
REGISTER_FOLD(SGE, I8, I8, I8);
REGISTER_FOLD(SGE, I8, I16, I16);
REGISTER_FOLD(SGE, I8, I32, I32);
REGISTER_FOLD(SGE, I8, I64, I64);
REGISTER_FOLD(SGE, I8, F32, F32);
REGISTER_FOLD(SGE, I8, F64, F64);
FOLD(ADD, ARG0_CNST | ARG1_CNST) { RESULT(ARG0() + ARG1()); }
REGISTER_FOLD(ADD, I8, I8, I8)
REGISTER_FOLD(ADD, I16, I16, I16)
REGISTER_FOLD(ADD, I32, I32, I32)
REGISTER_FOLD(ADD, I64, I64, I64)
REGISTER_FOLD(ADD, F32, F32, F32)
REGISTER_FOLD(ADD, F64, F64, F64)
REGISTER_FOLD(ADD, I8, I8, I8);
REGISTER_FOLD(ADD, I16, I16, I16);
REGISTER_FOLD(ADD, I32, I32, I32);
REGISTER_FOLD(ADD, I64, I64, I64);
REGISTER_FOLD(ADD, F32, F32, F32);
REGISTER_FOLD(ADD, F64, F64, F64);
FOLD(SUB, ARG0_CNST | ARG1_CNST) { RESULT(ARG0() - ARG1()); }
REGISTER_FOLD(SUB, I8, I8, I8)
REGISTER_FOLD(SUB, I16, I16, I16)
REGISTER_FOLD(SUB, I32, I32, I32)
REGISTER_FOLD(SUB, I64, I64, I64)
REGISTER_FOLD(SUB, F32, F32, F32)
REGISTER_FOLD(SUB, F64, F64, F64)
REGISTER_FOLD(SUB, I8, I8, I8);
REGISTER_FOLD(SUB, I16, I16, I16);
REGISTER_FOLD(SUB, I32, I32, I32);
REGISTER_FOLD(SUB, I64, I64, I64);
REGISTER_FOLD(SUB, F32, F32, F32);
REGISTER_FOLD(SUB, F64, F64, F64);
FOLD(AND, ARG0_CNST | ARG1_CNST) { RESULT(ARG0() & ARG1()); }
REGISTER_FOLD(AND, I8, I8, I8)
REGISTER_FOLD(AND, I16, I16, I16)
REGISTER_FOLD(AND, I32, I32, I32)
REGISTER_FOLD(AND, I64, I64, I64)
REGISTER_FOLD(AND, I8, I8, I8);
REGISTER_FOLD(AND, I16, I16, I16);
REGISTER_FOLD(AND, I32, I32, I32);
REGISTER_FOLD(AND, I64, I64, I64);
FOLD(OR, ARG0_CNST | ARG1_CNST) { RESULT(ARG0() | ARG1()); }
REGISTER_FOLD(OR, I8, I8, I8)
REGISTER_FOLD(OR, I16, I16, I16)
REGISTER_FOLD(OR, I32, I32, I32)
REGISTER_FOLD(OR, I64, I64, I64)
REGISTER_FOLD(OR, I8, I8, I8);
REGISTER_FOLD(OR, I16, I16, I16);
REGISTER_FOLD(OR, I32, I32, I32);
REGISTER_FOLD(OR, I64, I64, I64);
FOLD(XOR, ARG0_CNST | ARG1_CNST) { RESULT(ARG0() ^ ARG1()); }
REGISTER_FOLD(XOR, I8, I8, I8)
REGISTER_FOLD(XOR, I16, I16, I16)
REGISTER_FOLD(XOR, I32, I32, I32)
REGISTER_FOLD(XOR, I64, I64, I64)
REGISTER_FOLD(XOR, I8, I8, I8);
REGISTER_FOLD(XOR, I16, I16, I16);
REGISTER_FOLD(XOR, I32, I32, I32);
REGISTER_FOLD(XOR, I64, I64, I64);
FOLD(SHL, ARG0_CNST | ARG1_CNST) { RESULT(ARG0() << ARG1()); }
REGISTER_FOLD(SHL, I8, I8, I32)
REGISTER_FOLD(SHL, I16, I16, I32)
REGISTER_FOLD(SHL, I32, I32, I32)
REGISTER_FOLD(SHL, I64, I64, I32)
REGISTER_FOLD(SHL, I8, I8, I32);
REGISTER_FOLD(SHL, I16, I16, I32);
REGISTER_FOLD(SHL, I32, I32, I32);
REGISTER_FOLD(SHL, I64, I64, I32);
FOLD(LSHR, ARG0_CNST | ARG1_CNST) {
using U0 = typename std::make_unsigned<A0>::type;
RESULT((A0)((U0)ARG0() >> ARG1()));
}
REGISTER_FOLD(LSHR, I8, I8, I32)
REGISTER_FOLD(LSHR, I16, I16, I32)
REGISTER_FOLD(LSHR, I32, I32, I32)
REGISTER_FOLD(LSHR, I64, I64, I32)
REGISTER_FOLD(LSHR, I8, I8, I32);
REGISTER_FOLD(LSHR, I16, I16, I32);
REGISTER_FOLD(LSHR, I32, I32, I32);
REGISTER_FOLD(LSHR, I64, I64, I32);

View File

@ -16,22 +16,10 @@ void ValidateInstructionPass::Run(IRBuilder &builder) {
void ValidateInstructionPass::ValidateInstr(Instr *instr) {
// after constant propagation, there shouldn't be more than a single constant
// argument for most instructions
Opcode op = instr->op();
if (op != OP_STORE_CONTEXT && op != OP_BRANCH_COND && op != OP_SELECT) {
int num_constants = 0;
if (instr->arg0() && instr->arg0()->constant()) {
num_constants++;
}
if (instr->arg1() && instr->arg1()->constant()) {
num_constants++;
}
if (instr->arg2() && instr->arg2()->constant()) {
num_constants++;
}
if (num_constants > 1) {
LOG(FATAL) << "More than one constant argument detected for "
<< Opnames[op] << " instruction";
}
if (instr->op() != OP_STORE_CONTEXT && instr->arg0() &&
instr->arg0()->constant() && instr->arg1() && instr->arg1()->constant()) {
LOG(FATAL) << "More than one constant argument detected for "
<< Opnames[instr->op()] << " instruction";
}
// result (reg or local) should be equal to one of the incoming arguments