2018-08-12 00:11:13 +00:00
|
|
|
|
|
|
|
#include "jit.h"
|
|
|
|
#include "i_system.h"
|
2018-08-19 22:44:48 +00:00
|
|
|
#include "types.h"
|
2018-09-11 23:37:30 +00:00
|
|
|
#include "stats.h"
|
2018-08-12 00:11:13 +00:00
|
|
|
|
|
|
|
// To do: get cmake to define these..
|
|
|
|
#define ASMJIT_BUILD_EMBED
|
|
|
|
#define ASMJIT_STATIC
|
|
|
|
|
|
|
|
#include <asmjit/asmjit.h>
|
|
|
|
#include <asmjit/x86.h>
|
2018-08-14 14:07:09 +00:00
|
|
|
#include <functional>
|
2018-08-12 00:11:13 +00:00
|
|
|
|
2018-09-11 23:37:30 +00:00
|
|
|
extern cycle_t VMCycles[10];
|
|
|
|
extern int VMCalls[10];
|
|
|
|
|
2018-08-12 00:11:13 +00:00
|
|
|
#define A (pc[0].a)
|
|
|
|
#define B (pc[0].b)
|
|
|
|
#define C (pc[0].c)
|
|
|
|
#define Cs (pc[0].cs)
|
|
|
|
#define BC (pc[0].i16u)
|
|
|
|
#define BCs (pc[0].i16)
|
|
|
|
#define ABCs (pc[0].i24)
|
|
|
|
#define JMPOFS(x) ((x)->i24)
|
2018-08-13 16:07:36 +00:00
|
|
|
|
2018-08-26 12:27:46 +00:00
|
|
|
static const char *OpNames[NUM_OPS] =
|
|
|
|
{
|
|
|
|
#define xx(op, name, mode, alt, kreg, ktype) #op
|
|
|
|
#include "vmops.h"
|
|
|
|
};
|
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
class JitCompiler
|
2018-08-12 00:11:13 +00:00
|
|
|
{
|
2018-08-18 23:46:56 +00:00
|
|
|
public:
|
|
|
|
JitCompiler(asmjit::CodeHolder *code, VMScriptFunction *sfunc) : cc(code), sfunc(sfunc) { }
|
|
|
|
|
|
|
|
void Codegen()
|
2018-08-12 00:11:13 +00:00
|
|
|
{
|
2018-08-18 23:46:56 +00:00
|
|
|
using namespace asmjit;
|
2018-08-12 00:11:13 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
Setup();
|
|
|
|
|
2018-09-09 20:03:57 +00:00
|
|
|
pc = sfunc->Code;
|
|
|
|
auto end = pc + sfunc->CodeSize;
|
|
|
|
while (pc != end)
|
2018-08-18 23:46:56 +00:00
|
|
|
{
|
2018-09-09 20:03:57 +00:00
|
|
|
int i = (int)(ptrdiff_t)(pc - sfunc->Code);
|
2018-08-18 23:46:56 +00:00
|
|
|
op = pc->op;
|
|
|
|
|
|
|
|
cc.bind(labels[i]);
|
|
|
|
|
2018-08-26 12:27:46 +00:00
|
|
|
FString lineinfo;
|
2018-08-30 17:55:00 +00:00
|
|
|
lineinfo.Format("; %s(line %d): %02x%02x%02x%02x %s", sfunc->PrintableName.GetChars(), sfunc->PCToLine(pc), pc->op, pc->a, pc->b, pc->c, OpNames[op]);
|
2018-08-26 12:27:46 +00:00
|
|
|
cc.comment(lineinfo.GetChars(), lineinfo.Len());
|
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
EmitFuncPtr opcodeFunc = GetOpcodeEmitFunc(op);
|
|
|
|
if (!opcodeFunc)
|
|
|
|
I_FatalError("JIT error: Unknown VM opcode %d\n", op);
|
|
|
|
(this->*opcodeFunc)();
|
2018-09-09 20:03:57 +00:00
|
|
|
|
|
|
|
pc++;
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cc.endFunc();
|
|
|
|
cc.finalize();
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool CanJit(VMScriptFunction *sfunc)
|
|
|
|
{
|
|
|
|
int size = sfunc->CodeSize;
|
|
|
|
for (int i = 0; i < size; i++)
|
2018-08-12 00:11:13 +00:00
|
|
|
{
|
2018-08-18 23:46:56 +00:00
|
|
|
auto opcodeFunc = GetOpcodeEmitFunc(sfunc->Code[i].op);
|
|
|
|
if (!opcodeFunc)
|
|
|
|
return false;
|
|
|
|
|
2018-09-11 15:08:51 +00:00
|
|
|
auto pc = sfunc->Code + i;
|
2018-08-18 23:46:56 +00:00
|
|
|
if (sfunc->Code[i].op == OP_RET)
|
2018-08-12 00:11:13 +00:00
|
|
|
{
|
2018-08-18 23:46:56 +00:00
|
|
|
if (B != REGT_NIL)
|
2018-08-12 00:11:13 +00:00
|
|
|
{
|
2018-08-18 23:46:56 +00:00
|
|
|
int regtype = B;
|
2018-08-25 11:38:45 +00:00
|
|
|
if ((regtype & REGT_TYPE) == REGT_STRING)
|
2018-08-18 23:46:56 +00:00
|
|
|
return false;
|
2018-08-12 00:11:13 +00:00
|
|
|
}
|
|
|
|
}
|
2018-08-25 11:38:45 +00:00
|
|
|
else if (sfunc->Code[i].op == OP_CAST)
|
|
|
|
{
|
|
|
|
switch (C)
|
|
|
|
{
|
|
|
|
case CAST_I2F:
|
|
|
|
case CAST_U2F:
|
|
|
|
case CAST_F2I:
|
|
|
|
case CAST_F2U:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (sfunc->Code[i].op == OP_CASTB)
|
|
|
|
{
|
|
|
|
if (C == CASTB_S)
|
|
|
|
return false;
|
|
|
|
}
|
2018-09-11 15:08:51 +00:00
|
|
|
else if (sfunc->Code[i].op == OP_PARAM)
|
|
|
|
{
|
2018-09-12 19:58:31 +00:00
|
|
|
if (!!(B & REGT_MULTIREG3) || !!(B & REGT_MULTIREG2))
|
|
|
|
return false;
|
|
|
|
|
2018-09-11 15:08:51 +00:00
|
|
|
switch (B)
|
|
|
|
{
|
|
|
|
case REGT_STRING:
|
|
|
|
case REGT_STRING | REGT_ADDROF:
|
|
|
|
case REGT_STRING | REGT_KONST:
|
|
|
|
return false;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-09-11 23:37:30 +00:00
|
|
|
else if (sfunc->Code[i].op == OP_RESULT)
|
|
|
|
{
|
2018-09-12 19:58:31 +00:00
|
|
|
if (!!(B & REGT_MULTIREG3) || !!(B & REGT_MULTIREG2))
|
|
|
|
return false;
|
|
|
|
|
2018-09-11 23:37:30 +00:00
|
|
|
if ((B & REGT_TYPE) == REGT_STRING)
|
|
|
|
return false;
|
|
|
|
}
|
2018-08-12 00:11:13 +00:00
|
|
|
}
|
2018-08-18 23:46:56 +00:00
|
|
|
return true;
|
2018-08-12 00:11:13 +00:00
|
|
|
}
|
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
private:
|
|
|
|
typedef void(JitCompiler::*EmitFuncPtr)();
|
2018-08-14 14:07:09 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
static EmitFuncPtr GetOpcodeEmitFunc(VM_UBYTE op)
|
|
|
|
{
|
|
|
|
#define EMIT_OP(x) case OP_##x: return &JitCompiler::Emit##x
|
2018-08-14 14:07:09 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
switch (op)
|
|
|
|
{
|
|
|
|
default: return nullptr;
|
|
|
|
EMIT_OP(NOP);
|
|
|
|
EMIT_OP(LI);
|
|
|
|
EMIT_OP(LK);
|
|
|
|
EMIT_OP(LKF);
|
|
|
|
// EMIT_OP(LKS);
|
|
|
|
EMIT_OP(LKP);
|
|
|
|
EMIT_OP(LK_R);
|
|
|
|
EMIT_OP(LKF_R);
|
|
|
|
// EMIT_OP(LKS_R);
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EMIT_OP(LKP_R);
|
2018-08-18 23:46:56 +00:00
|
|
|
// EMIT_OP(LFP);
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EMIT_OP(META);
|
|
|
|
EMIT_OP(CLSS);
|
2018-08-18 23:46:56 +00:00
|
|
|
EMIT_OP(LB);
|
|
|
|
EMIT_OP(LB_R);
|
|
|
|
EMIT_OP(LH);
|
|
|
|
EMIT_OP(LH_R);
|
|
|
|
EMIT_OP(LW);
|
|
|
|
EMIT_OP(LW_R);
|
|
|
|
EMIT_OP(LBU);
|
|
|
|
EMIT_OP(LBU_R);
|
|
|
|
EMIT_OP(LHU);
|
|
|
|
EMIT_OP(LHU_R);
|
|
|
|
EMIT_OP(LSP);
|
|
|
|
EMIT_OP(LSP_R);
|
|
|
|
EMIT_OP(LDP);
|
|
|
|
EMIT_OP(LDP_R);
|
|
|
|
// EMIT_OP(LS);
|
|
|
|
// EMIT_OP(LS_R);
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EMIT_OP(LO);
|
|
|
|
EMIT_OP(LO_R);
|
|
|
|
EMIT_OP(LP);
|
|
|
|
EMIT_OP(LP_R);
|
2018-08-18 23:46:56 +00:00
|
|
|
EMIT_OP(LV2);
|
|
|
|
EMIT_OP(LV2_R);
|
|
|
|
EMIT_OP(LV3);
|
|
|
|
EMIT_OP(LV3_R);
|
|
|
|
//EMIT_OP(LCS);
|
|
|
|
//EMIT_OP(LCS_R);
|
2018-09-02 01:39:02 +00:00
|
|
|
EMIT_OP(LBIT);
|
2018-08-18 23:46:56 +00:00
|
|
|
EMIT_OP(SB);
|
|
|
|
EMIT_OP(SB_R);
|
|
|
|
EMIT_OP(SH);
|
|
|
|
EMIT_OP(SH_R);
|
|
|
|
EMIT_OP(SW);
|
|
|
|
EMIT_OP(SW_R);
|
|
|
|
EMIT_OP(SSP);
|
|
|
|
EMIT_OP(SSP_R);
|
|
|
|
EMIT_OP(SDP);
|
|
|
|
EMIT_OP(SDP_R);
|
|
|
|
//EMIT_OP(SS);
|
|
|
|
//EMIT_OP(SS_R);
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EMIT_OP(SO);
|
|
|
|
EMIT_OP(SO_R);
|
|
|
|
EMIT_OP(SP);
|
|
|
|
EMIT_OP(SP_R);
|
2018-08-18 23:46:56 +00:00
|
|
|
EMIT_OP(SV2);
|
|
|
|
EMIT_OP(SV2_R);
|
|
|
|
EMIT_OP(SV3);
|
|
|
|
EMIT_OP(SV3_R);
|
2018-09-02 01:39:02 +00:00
|
|
|
EMIT_OP(SBIT);
|
2018-08-18 23:46:56 +00:00
|
|
|
EMIT_OP(MOVE);
|
|
|
|
EMIT_OP(MOVEF);
|
|
|
|
// EMIT_OP(MOVES);
|
2018-08-19 22:44:48 +00:00
|
|
|
EMIT_OP(MOVEA);
|
2018-08-18 23:46:56 +00:00
|
|
|
EMIT_OP(MOVEV2);
|
|
|
|
EMIT_OP(MOVEV3);
|
2018-08-25 11:38:45 +00:00
|
|
|
EMIT_OP(CAST);
|
|
|
|
EMIT_OP(CASTB);
|
2018-08-19 22:44:48 +00:00
|
|
|
EMIT_OP(DYNCAST_R);
|
|
|
|
EMIT_OP(DYNCAST_K);
|
|
|
|
EMIT_OP(DYNCASTC_R);
|
|
|
|
EMIT_OP(DYNCASTC_K);
|
|
|
|
EMIT_OP(TEST);
|
|
|
|
EMIT_OP(TESTN);
|
|
|
|
EMIT_OP(JMP);
|
2018-08-18 23:46:56 +00:00
|
|
|
//EMIT_OP(IJMP);
|
2018-09-11 15:08:51 +00:00
|
|
|
EMIT_OP(PARAM);
|
|
|
|
EMIT_OP(PARAMI);
|
2018-09-12 19:58:31 +00:00
|
|
|
//EMIT_OP(CALL);
|
2018-09-11 23:37:30 +00:00
|
|
|
EMIT_OP(CALL_K);
|
2018-09-02 01:39:02 +00:00
|
|
|
EMIT_OP(VTBL);
|
|
|
|
EMIT_OP(SCOPE);
|
2018-08-18 23:46:56 +00:00
|
|
|
//EMIT_OP(TAIL);
|
|
|
|
//EMIT_OP(TAIL_K);
|
2018-08-19 23:40:37 +00:00
|
|
|
EMIT_OP(RESULT);
|
2018-08-18 23:46:56 +00:00
|
|
|
EMIT_OP(RET);
|
|
|
|
EMIT_OP(RETI);
|
2018-09-02 01:39:02 +00:00
|
|
|
EMIT_OP(NEW);
|
|
|
|
EMIT_OP(NEW_K);
|
|
|
|
EMIT_OP(THROW);
|
2018-08-26 12:27:46 +00:00
|
|
|
EMIT_OP(BOUND);
|
|
|
|
EMIT_OP(BOUND_K);
|
|
|
|
EMIT_OP(BOUND_R);
|
2018-08-18 23:46:56 +00:00
|
|
|
//EMIT_OP(CONCAT);
|
|
|
|
//EMIT_OP(LENS);
|
|
|
|
//EMIT_OP(CMPS);
|
|
|
|
EMIT_OP(SLL_RR);
|
|
|
|
EMIT_OP(SLL_RI);
|
|
|
|
EMIT_OP(SLL_KR);
|
|
|
|
EMIT_OP(SRL_RR);
|
|
|
|
EMIT_OP(SRL_RI);
|
|
|
|
EMIT_OP(SRL_KR);
|
|
|
|
EMIT_OP(SRA_RR);
|
|
|
|
EMIT_OP(SRA_RI);
|
|
|
|
EMIT_OP(SRA_KR);
|
|
|
|
EMIT_OP(ADD_RR);
|
|
|
|
EMIT_OP(ADD_RK);
|
|
|
|
EMIT_OP(ADDI);
|
|
|
|
EMIT_OP(SUB_RR);
|
|
|
|
EMIT_OP(SUB_RK);
|
|
|
|
EMIT_OP(SUB_KR);
|
|
|
|
EMIT_OP(MUL_RR);
|
|
|
|
EMIT_OP(MUL_RK);
|
|
|
|
EMIT_OP(DIV_RR);
|
|
|
|
EMIT_OP(DIV_RK);
|
|
|
|
EMIT_OP(DIV_KR);
|
|
|
|
EMIT_OP(DIVU_RR);
|
|
|
|
EMIT_OP(DIVU_RK);
|
|
|
|
EMIT_OP(DIVU_KR);
|
|
|
|
EMIT_OP(MOD_RR);
|
|
|
|
EMIT_OP(MOD_RK);
|
|
|
|
EMIT_OP(MOD_KR);
|
|
|
|
EMIT_OP(MODU_RR);
|
|
|
|
EMIT_OP(MODU_RK);
|
|
|
|
EMIT_OP(MODU_KR);
|
|
|
|
EMIT_OP(AND_RR);
|
|
|
|
EMIT_OP(AND_RK);
|
|
|
|
EMIT_OP(OR_RR);
|
|
|
|
EMIT_OP(OR_RK);
|
|
|
|
EMIT_OP(XOR_RR);
|
|
|
|
EMIT_OP(XOR_RK);
|
|
|
|
EMIT_OP(MIN_RR);
|
|
|
|
EMIT_OP(MIN_RK);
|
|
|
|
EMIT_OP(MAX_RR);
|
|
|
|
EMIT_OP(MAX_RK);
|
|
|
|
EMIT_OP(ABS);
|
|
|
|
EMIT_OP(NEG);
|
|
|
|
EMIT_OP(NOT);
|
|
|
|
EMIT_OP(EQ_R);
|
|
|
|
EMIT_OP(EQ_K);
|
|
|
|
EMIT_OP(LT_RR);
|
|
|
|
EMIT_OP(LT_RK);
|
|
|
|
EMIT_OP(LT_KR);
|
|
|
|
EMIT_OP(LE_RR);
|
|
|
|
EMIT_OP(LE_RK);
|
|
|
|
EMIT_OP(LE_KR);
|
|
|
|
EMIT_OP(LTU_RR);
|
|
|
|
EMIT_OP(LTU_RK);
|
|
|
|
EMIT_OP(LTU_KR);
|
|
|
|
EMIT_OP(LEU_RR);
|
|
|
|
EMIT_OP(LEU_RK);
|
|
|
|
EMIT_OP(LEU_KR);
|
|
|
|
EMIT_OP(ADDF_RR);
|
|
|
|
EMIT_OP(ADDF_RK);
|
|
|
|
EMIT_OP(SUBF_RR);
|
|
|
|
EMIT_OP(SUBF_RK);
|
|
|
|
EMIT_OP(SUBF_KR);
|
|
|
|
EMIT_OP(MULF_RR);
|
|
|
|
EMIT_OP(MULF_RK);
|
|
|
|
EMIT_OP(DIVF_RR);
|
|
|
|
EMIT_OP(DIVF_RK);
|
|
|
|
EMIT_OP(DIVF_KR);
|
2018-08-28 23:27:37 +00:00
|
|
|
EMIT_OP(MODF_RR);
|
|
|
|
EMIT_OP(MODF_RK);
|
|
|
|
EMIT_OP(MODF_KR);
|
2018-08-24 21:17:35 +00:00
|
|
|
EMIT_OP(POWF_RR);
|
|
|
|
EMIT_OP(POWF_RK);
|
|
|
|
EMIT_OP(POWF_KR);
|
|
|
|
EMIT_OP(MINF_RR);
|
|
|
|
EMIT_OP(MINF_RK);
|
|
|
|
EMIT_OP(MAXF_RR);
|
|
|
|
EMIT_OP(MAXF_RK);
|
2018-08-19 23:40:37 +00:00
|
|
|
EMIT_OP(ATAN2);
|
|
|
|
EMIT_OP(FLOP);
|
2018-08-18 23:46:56 +00:00
|
|
|
EMIT_OP(EQF_R);
|
|
|
|
EMIT_OP(EQF_K);
|
|
|
|
EMIT_OP(LTF_RR);
|
|
|
|
EMIT_OP(LTF_RK);
|
|
|
|
EMIT_OP(LTF_KR);
|
|
|
|
EMIT_OP(LEF_RR);
|
|
|
|
EMIT_OP(LEF_RK);
|
|
|
|
EMIT_OP(LEF_KR);
|
|
|
|
EMIT_OP(NEGV2);
|
|
|
|
EMIT_OP(ADDV2_RR);
|
|
|
|
EMIT_OP(SUBV2_RR);
|
|
|
|
EMIT_OP(DOTV2_RR);
|
|
|
|
EMIT_OP(MULVF2_RR);
|
|
|
|
EMIT_OP(MULVF2_RK);
|
|
|
|
EMIT_OP(DIVVF2_RR);
|
|
|
|
EMIT_OP(DIVVF2_RK);
|
|
|
|
EMIT_OP(LENV2);
|
2018-09-02 22:44:25 +00:00
|
|
|
EMIT_OP(EQV2_R);
|
|
|
|
EMIT_OP(EQV2_K);
|
2018-08-18 23:46:56 +00:00
|
|
|
EMIT_OP(NEGV3);
|
|
|
|
EMIT_OP(ADDV3_RR);
|
|
|
|
EMIT_OP(SUBV3_RR);
|
|
|
|
EMIT_OP(DOTV3_RR);
|
|
|
|
EMIT_OP(CROSSV_RR);
|
|
|
|
EMIT_OP(MULVF3_RR);
|
|
|
|
EMIT_OP(MULVF3_RK);
|
|
|
|
EMIT_OP(DIVVF3_RR);
|
|
|
|
EMIT_OP(DIVVF3_RK);
|
|
|
|
EMIT_OP(LENV3);
|
2018-09-02 22:44:25 +00:00
|
|
|
EMIT_OP(EQV3_R);
|
|
|
|
EMIT_OP(EQV3_K);
|
2018-08-18 23:46:56 +00:00
|
|
|
EMIT_OP(ADDA_RR);
|
|
|
|
EMIT_OP(ADDA_RK);
|
|
|
|
EMIT_OP(SUBA);
|
2018-09-02 01:39:02 +00:00
|
|
|
EMIT_OP(EQA_R);
|
|
|
|
EMIT_OP(EQA_K);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
}
|
2018-08-14 14:07:09 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitNOP()
|
|
|
|
{
|
|
|
|
cc.nop();
|
|
|
|
}
|
2018-08-14 14:07:09 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
// Load constants.
|
2018-08-14 14:07:09 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLI()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(regD[A], BCs);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-14 14:07:09 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLK()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(regD[A], konstd[BC]);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-18 10:37:33 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLKF()
|
|
|
|
{
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, ToMemAddress(konstf + BC));
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsd(regF[A], asmjit::x86::qword_ptr(tmp));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-18 17:03:18 +00:00
|
|
|
|
2018-09-02 13:36:39 +00:00
|
|
|
//void EmitLKS() { } // load string constant
|
2018-08-18 17:03:18 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLKP()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(regA[A], (int64_t)konsta[BC].v);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-18 17:03:18 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLK_R()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(regD[A], asmjit::x86::ptr(ToMemAddress(konstd), regD[B], 2, C * sizeof(int32_t)));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-18 20:41:18 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLKF_R()
|
|
|
|
{
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, ToMemAddress(konstf + BC));
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsd(regF[A], asmjit::x86::qword_ptr(tmp, regD[B], 3, C * sizeof(double)));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-18 16:41:35 +00:00
|
|
|
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
//void EmitLKS_R() { } // load string constant indexed
|
2018-08-12 00:11:13 +00:00
|
|
|
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
void EmitLKP_R()
|
2018-08-12 00:11:13 +00:00
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(regA[A], asmjit::x86::ptr(ToMemAddress(konsta), regD[B], 2, C * sizeof(void*)));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-18 15:50:47 +00:00
|
|
|
|
2018-09-02 13:36:39 +00:00
|
|
|
//void EmitLFP() { } // load frame pointer
|
2018-08-12 00:11:13 +00:00
|
|
|
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
void EmitMETA()
|
2018-08-18 23:46:56 +00:00
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
typedef void*(*FuncPtr)(void*);
|
|
|
|
|
|
|
|
auto label = cc.newLabel();
|
|
|
|
cc.test(regA[B], regA[B]);
|
|
|
|
cc.jne(label);
|
|
|
|
EmitThrowException(X_READ_NIL);
|
|
|
|
cc.bind(label);
|
|
|
|
|
|
|
|
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(static_cast<FuncPtr>([](void *o) -> void*
|
|
|
|
{
|
2018-09-09 20:42:59 +00:00
|
|
|
return static_cast<DObject*>(o)->GetClass()->Meta;
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
}))), asmjit::FuncSignature1<void*, void*>());
|
2018-09-02 13:36:39 +00:00
|
|
|
call->setRet(0, regA[A]);
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
call->setArg(0, regA[B]);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-12 00:11:13 +00:00
|
|
|
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
void EmitCLSS()
|
2018-08-18 23:46:56 +00:00
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
typedef void*(*FuncPtr)(void*);
|
|
|
|
|
|
|
|
auto label = cc.newLabel();
|
|
|
|
cc.test(regA[B], regA[B]);
|
|
|
|
cc.jne(label);
|
|
|
|
EmitThrowException(X_READ_NIL);
|
|
|
|
cc.bind(label);
|
|
|
|
|
|
|
|
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(static_cast<FuncPtr>([](void *o) -> void*
|
|
|
|
{
|
2018-09-09 20:42:59 +00:00
|
|
|
return static_cast<DObject*>(o)->GetClass();
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
}))), asmjit::FuncSignature1<void*, void*>());
|
2018-09-02 13:36:39 +00:00
|
|
|
call->setRet(0, regA[A]);
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
call->setArg(0, regA[B]);
|
|
|
|
}
|
2018-08-12 00:11:13 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
// Load from memory. rA = *(rB + rkC)
|
2018-08-12 00:11:13 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLB()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(B, X_READ_NIL);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsx(regD[A], asmjit::x86::byte_ptr(regA[B], konstd[C]));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-12 00:11:13 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLB_R()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(B, X_READ_NIL);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsx(regD[A], asmjit::x86::byte_ptr(regA[B], regD[C]));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-12 00:11:13 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLH()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(B, X_READ_NIL);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsx(regD[A], asmjit::x86::word_ptr(regA[B], konstd[C]));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-12 22:15:42 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLH_R()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(B, X_READ_NIL);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsx(regD[A], asmjit::x86::word_ptr(regA[B], regD[C]));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-12 00:11:13 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLW()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(B, X_READ_NIL);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(regD[A], asmjit::x86::dword_ptr(regA[B], konstd[C]));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-14 12:02:56 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLW_R()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(B, X_READ_NIL);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(regD[A], asmjit::x86::dword_ptr(regA[B], regD[C]));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-14 12:02:56 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLBU()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(B, X_READ_NIL);
|
2018-09-09 21:21:47 +00:00
|
|
|
cc.movzx(regD[A], asmjit::x86::byte_ptr(regA[B], konstd[C]));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-14 12:02:56 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLBU_R()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(B, X_READ_NIL);
|
2018-09-09 21:21:47 +00:00
|
|
|
cc.movzx(regD[A].r8Lo(), asmjit::x86::byte_ptr(regA[B], regD[C]));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-12 00:11:13 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLHU()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(B, X_READ_NIL);
|
2018-09-09 21:21:47 +00:00
|
|
|
cc.movzx(regD[A].r16(), asmjit::x86::word_ptr(regA[B], konstd[C]));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-14 12:02:56 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLHU_R()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(B, X_READ_NIL);
|
2018-09-09 21:21:47 +00:00
|
|
|
cc.movzx(regD[A].r16(), asmjit::x86::word_ptr(regA[B], regD[C]));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-12 00:11:13 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLSP()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(B, X_READ_NIL);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movss(regF[A], asmjit::x86::dword_ptr(regA[B], konstd[C]));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-12 00:11:13 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLSP_R()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(B, X_READ_NIL);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movss(regF[A], asmjit::x86::dword_ptr(regA[B], regD[C]));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-12 00:11:13 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLDP()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(B, X_READ_NIL);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsd(regF[A], asmjit::x86::qword_ptr(regA[B], konstd[C]));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitLDP_R()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(B, X_READ_NIL);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsd(regF[A], asmjit::x86::qword_ptr(regA[B], regD[C]));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
2018-09-02 13:36:39 +00:00
|
|
|
//void EmitLS() { } // load string
|
|
|
|
//void EmitLS_R() { }
|
2018-08-18 23:46:56 +00:00
|
|
|
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
void EmitLO()
|
2018-08-18 23:46:56 +00:00
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(B, X_READ_NIL);
|
|
|
|
|
|
|
|
auto ptr = cc.newIntPtr();
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(ptr, asmjit::x86::ptr(regA[B], konstd[C]));
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
|
|
|
|
typedef void*(*FuncPtr)(void*);
|
|
|
|
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(static_cast<FuncPtr>([](void *ptr) -> void*
|
|
|
|
{
|
|
|
|
DObject *p = static_cast<DObject *>(ptr);
|
|
|
|
return GC::ReadBarrier(p);
|
|
|
|
}))), asmjit::FuncSignature1<void*, void*>());
|
2018-09-02 13:36:39 +00:00
|
|
|
call->setRet(0, regA[A]);
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
call->setArg(0, ptr);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitLO_R()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(B, X_READ_NIL);
|
|
|
|
|
|
|
|
auto ptr = cc.newIntPtr();
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(ptr, asmjit::x86::ptr(regA[B], regD[C]));
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
|
|
|
|
typedef void*(*FuncPtr)(void*);
|
|
|
|
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(static_cast<FuncPtr>([](void *ptr) -> void*
|
|
|
|
{
|
|
|
|
DObject *p = static_cast<DObject *>(ptr);
|
|
|
|
return GC::ReadBarrier(p);
|
|
|
|
}))), asmjit::FuncSignature1<void*, void*>());
|
2018-09-02 13:36:39 +00:00
|
|
|
call->setRet(0, regA[A]);
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
call->setArg(0, ptr);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
void EmitLP()
|
2018-08-18 23:46:56 +00:00
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(B, X_READ_NIL);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(regA[A], asmjit::x86::ptr(regA[B], konstd[C]));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitLP_R()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(B, X_READ_NIL);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(regA[A], asmjit::x86::ptr(regA[B], regD[C]));
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
}
|
2018-08-18 23:46:56 +00:00
|
|
|
|
|
|
|
void EmitLV2()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(B, X_READ_NIL);
|
2018-08-18 23:46:56 +00:00
|
|
|
auto tmp = cc.newIntPtr();
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(tmp, regA[B]);
|
|
|
|
cc.add(tmp, konstd[C]);
|
|
|
|
cc.movsd(regF[A], asmjit::x86::qword_ptr(tmp));
|
|
|
|
cc.movsd(regF[A + 1], asmjit::x86::qword_ptr(tmp, 8));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitLV2_R()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(B, X_READ_NIL);
|
2018-08-18 23:46:56 +00:00
|
|
|
auto tmp = cc.newIntPtr();
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(tmp, regA[B]);
|
|
|
|
cc.add(tmp, regD[C]);
|
|
|
|
cc.movsd(regF[A], asmjit::x86::qword_ptr(tmp));
|
|
|
|
cc.movsd(regF[A + 1], asmjit::x86::qword_ptr(tmp, 8));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitLV3()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(B, X_READ_NIL);
|
2018-08-18 23:46:56 +00:00
|
|
|
auto tmp = cc.newIntPtr();
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(tmp, regA[B]);
|
|
|
|
cc.add(tmp, konstd[C]);
|
|
|
|
cc.movsd(regF[A], asmjit::x86::qword_ptr(tmp));
|
|
|
|
cc.movsd(regF[A + 1], asmjit::x86::qword_ptr(tmp, 8));
|
|
|
|
cc.movsd(regF[A + 2], asmjit::x86::qword_ptr(tmp, 16));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitLV3_R()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(B, X_READ_NIL);
|
2018-08-18 23:46:56 +00:00
|
|
|
auto tmp = cc.newIntPtr();
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(tmp, regA[B]);
|
|
|
|
cc.add(tmp, regD[C]);
|
|
|
|
cc.movsd(regF[A], asmjit::x86::qword_ptr(tmp));
|
|
|
|
cc.movsd(regF[A + 1], asmjit::x86::qword_ptr(tmp, 8));
|
|
|
|
cc.movsd(regF[A + 2], asmjit::x86::qword_ptr(tmp, 16));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
2018-09-02 13:36:39 +00:00
|
|
|
//void EmitLCS() { } // load string from char ptr.
|
|
|
|
//void EmitLCS_R() { }
|
2018-08-18 23:46:56 +00:00
|
|
|
|
2018-09-02 01:39:02 +00:00
|
|
|
void EmitLBIT()
|
2018-08-18 23:46:56 +00:00
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(B, X_READ_NIL);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsx(regD[A], asmjit::x86::byte_ptr(regA[B]));
|
|
|
|
cc.and_(regD[A], C);
|
|
|
|
cc.cmp(regD[A], 0);
|
|
|
|
cc.setne(regD[A]);
|
2018-09-02 01:39:02 +00:00
|
|
|
}
|
2018-08-18 23:46:56 +00:00
|
|
|
|
|
|
|
// Store instructions. *(rA + rkC) = rB
|
|
|
|
|
|
|
|
void EmitSB()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(A, X_WRITE_NIL);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(asmjit::x86::byte_ptr(regA[A], konstd[C]), regD[B].r8Lo());
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSB_R()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(A, X_WRITE_NIL);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(asmjit::x86::byte_ptr(regA[A], regD[C]), regD[B].r8Lo());
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSH()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(A, X_WRITE_NIL);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(asmjit::x86::word_ptr(regA[A], konstd[C]), regD[B].r16());
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSH_R()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(A, X_WRITE_NIL);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(asmjit::x86::word_ptr(regA[A], regD[C]), regD[B].r16());
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSW()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(A, X_WRITE_NIL);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(asmjit::x86::dword_ptr(regA[A], konstd[C]), regD[B]);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSW_R()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(A, X_WRITE_NIL);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(asmjit::x86::dword_ptr(regA[A], regD[C]), regD[B]);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSSP()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(A, X_WRITE_NIL);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movss(asmjit::x86::dword_ptr(regA[A], konstd[C]), regF[B]);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSSP_R()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(A, X_WRITE_NIL);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movss(asmjit::x86::dword_ptr(regA[A], regD[C]), regF[B]);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSDP()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(A, X_WRITE_NIL);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsd(asmjit::x86::qword_ptr(regA[A], konstd[C]), regF[B]);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSDP_R()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(A, X_WRITE_NIL);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsd(asmjit::x86::qword_ptr(regA[A], regD[C]), regF[B]);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//void EmitSS() {} // store string
|
|
|
|
//void EmitSS_R() {}
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
|
|
|
|
void EmitSO()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(asmjit::x86::ptr(regA[A], konstd[C]), regA[B]);
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
|
|
|
|
typedef void(*FuncPtr)(DObject*);
|
|
|
|
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(static_cast<FuncPtr>(GC::WriteBarrier))), asmjit::FuncSignature1<void, void*>());
|
|
|
|
call->setArg(0, regA[B]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSO_R()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(asmjit::x86::ptr(regA[A], regD[C]), regA[B]);
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
|
|
|
|
typedef void(*FuncPtr)(DObject*);
|
|
|
|
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(static_cast<FuncPtr>(GC::WriteBarrier))), asmjit::FuncSignature1<void, void*>());
|
|
|
|
call->setArg(0, regA[B]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSP()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(asmjit::x86::ptr(regA[A], konstd[C]), regA[B]);
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSP_R()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(asmjit::x86::ptr(regA[A], regD[C]), regA[B]);
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
}
|
2018-08-18 23:46:56 +00:00
|
|
|
|
|
|
|
void EmitSV2()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(B, X_WRITE_NIL);
|
2018-08-18 23:46:56 +00:00
|
|
|
auto tmp = cc.newIntPtr();
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(tmp, regA[B]);
|
|
|
|
cc.add(tmp, konstd[C]);
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.movsd(asmjit::x86::qword_ptr(tmp), regF[B]);
|
|
|
|
cc.movsd(asmjit::x86::qword_ptr(tmp, 8), regF[B + 1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSV2_R()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(B, X_WRITE_NIL);
|
2018-08-18 23:46:56 +00:00
|
|
|
auto tmp = cc.newIntPtr();
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(tmp, regA[B]);
|
|
|
|
cc.add(tmp, regD[C]);
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.movsd(asmjit::x86::qword_ptr(tmp), regF[B]);
|
|
|
|
cc.movsd(asmjit::x86::qword_ptr(tmp, 8), regF[B + 1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSV3()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(B, X_WRITE_NIL);
|
2018-08-18 23:46:56 +00:00
|
|
|
auto tmp = cc.newIntPtr();
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(tmp, regA[B]);
|
|
|
|
cc.add(tmp, konstd[C]);
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.movsd(asmjit::x86::qword_ptr(tmp), regF[B]);
|
|
|
|
cc.movsd(asmjit::x86::qword_ptr(tmp, 8), regF[B + 1]);
|
|
|
|
cc.movsd(asmjit::x86::qword_ptr(tmp, 16), regF[B + 2]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSV3_R()
|
|
|
|
{
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
EmitNullPointerThrow(B, X_WRITE_NIL);
|
2018-08-18 23:46:56 +00:00
|
|
|
auto tmp = cc.newIntPtr();
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(tmp, regA[B]);
|
|
|
|
cc.add(tmp, regD[C]);
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.movsd(asmjit::x86::qword_ptr(tmp), regF[B]);
|
|
|
|
cc.movsd(asmjit::x86::qword_ptr(tmp, 8), regF[B + 1]);
|
|
|
|
cc.movsd(asmjit::x86::qword_ptr(tmp, 16), regF[B + 2]);
|
|
|
|
}
|
|
|
|
|
2018-09-02 01:39:02 +00:00
|
|
|
void EmitSBIT()
|
|
|
|
{
|
|
|
|
EmitNullPointerThrow(B, X_WRITE_NIL);
|
|
|
|
auto tmp1 = cc.newInt32();
|
|
|
|
auto tmp2 = cc.newInt32();
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(tmp1, asmjit::x86::byte_ptr(regA[A]));
|
2018-09-02 01:39:02 +00:00
|
|
|
cc.mov(tmp2, tmp1);
|
|
|
|
cc.or_(tmp1, (int)C);
|
|
|
|
cc.and_(tmp2, ~(int)C);
|
|
|
|
cc.test(regD[B], regD[B]);
|
|
|
|
cc.cmove(tmp1, tmp2);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(asmjit::x86::byte_ptr(regA[A]), tmp1);
|
2018-09-02 01:39:02 +00:00
|
|
|
}
|
2018-08-18 23:46:56 +00:00
|
|
|
|
|
|
|
// Move instructions.
|
|
|
|
|
|
|
|
void EmitMOVE()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(regD[A], regD[B]);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
void EmitMOVEF()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsd(regF[A], regF[B]);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// void EmitMOVES() {} // sA = sB
|
2018-08-19 22:44:48 +00:00
|
|
|
|
|
|
|
void EmitMOVEA()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(regA[A], regA[B]);
|
2018-08-19 22:44:48 +00:00
|
|
|
}
|
2018-08-18 23:46:56 +00:00
|
|
|
|
|
|
|
void EmitMOVEV2()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsd(regF[A], regF[B]);
|
|
|
|
cc.movsd(regF[A + 1], regF[B + 1]);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitMOVEV3()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsd(regF[A], regF[B]);
|
|
|
|
cc.movsd(regF[A + 1], regF[B + 1]);
|
|
|
|
cc.movsd(regF[A + 2], regF[B + 2]);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
2018-08-25 11:38:45 +00:00
|
|
|
void EmitCAST()
|
|
|
|
{
|
|
|
|
switch (C)
|
|
|
|
{
|
|
|
|
case CAST_I2F:
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.cvtsi2sd(regF[A], regD[B]);
|
2018-08-25 11:38:45 +00:00
|
|
|
break;
|
|
|
|
case CAST_U2F:
|
|
|
|
{
|
|
|
|
auto tmp = cc.newInt64();
|
|
|
|
cc.xor_(tmp, tmp);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(tmp.r32(), regD[B]);
|
|
|
|
cc.cvtsi2sd(regF[A], tmp);
|
2018-08-25 11:38:45 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CAST_F2I:
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.cvttsd2si(regD[A], regF[B]);
|
2018-08-25 11:38:45 +00:00
|
|
|
break;
|
|
|
|
case CAST_F2U:
|
|
|
|
{
|
|
|
|
auto tmp = cc.newInt64();
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.cvttsd2si(tmp, regF[B]);
|
|
|
|
cc.mov(regD[A], tmp.r32());
|
2018-08-25 11:38:45 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*case CAST_I2S:
|
2018-09-02 13:36:39 +00:00
|
|
|
reg.s[A].Format("%d", reg.d[B]);
|
2018-08-25 11:38:45 +00:00
|
|
|
break;
|
|
|
|
case CAST_U2S:
|
2018-09-02 13:36:39 +00:00
|
|
|
reg.s[A].Format("%u", reg.d[B]);
|
2018-08-25 11:38:45 +00:00
|
|
|
break;
|
|
|
|
case CAST_F2S:
|
2018-09-02 13:36:39 +00:00
|
|
|
reg.s[A].Format("%.5f", reg.f[B]); // keep this small. For more precise conversion there should be a conversion function.
|
2018-08-25 11:38:45 +00:00
|
|
|
break;
|
|
|
|
case CAST_V22S:
|
2018-09-02 13:36:39 +00:00
|
|
|
reg.s[A].Format("(%.5f, %.5f)", reg.f[B], reg.f[b + 1]);
|
2018-08-25 11:38:45 +00:00
|
|
|
break;
|
|
|
|
case CAST_V32S:
|
2018-09-02 13:36:39 +00:00
|
|
|
reg.s[A].Format("(%.5f, %.5f, %.5f)", reg.f[B], reg.f[b + 1], reg.f[b + 2]);
|
2018-08-25 11:38:45 +00:00
|
|
|
break;
|
|
|
|
case CAST_P2S:
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
if (reg.a[B] == nullptr) reg.s[A] = "null";
|
|
|
|
else reg.s[A].Format("%p", reg.a[B]);
|
2018-08-25 11:38:45 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CAST_S2I:
|
2018-09-02 13:36:39 +00:00
|
|
|
reg.d[A] = (VM_SWORD)reg.s[B].ToLong();
|
2018-08-25 11:38:45 +00:00
|
|
|
break;
|
|
|
|
case CAST_S2F:
|
2018-09-02 13:36:39 +00:00
|
|
|
reg.f[A] = reg.s[B].ToDouble();
|
2018-08-25 11:38:45 +00:00
|
|
|
break;
|
|
|
|
case CAST_S2N:
|
2018-09-02 13:36:39 +00:00
|
|
|
reg.d[A] = reg.s[B].Len() == 0 ? FName(NAME_None) : FName(reg.s[B]);
|
2018-08-25 11:38:45 +00:00
|
|
|
break;
|
|
|
|
case CAST_N2S:
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
FName name = FName(ENamedName(reg.d[B]));
|
|
|
|
reg.s[A] = name.IsValidName() ? name.GetChars() : "";
|
2018-08-25 11:38:45 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CAST_S2Co:
|
2018-09-02 13:36:39 +00:00
|
|
|
reg.d[A] = V_GetColor(NULL, reg.s[B]);
|
2018-08-25 11:38:45 +00:00
|
|
|
break;
|
|
|
|
case CAST_Co2S:
|
2018-09-02 13:36:39 +00:00
|
|
|
reg.s[A].Format("%02x %02x %02x", PalEntry(reg.d[B]).r, PalEntry(reg.d[B]).g, PalEntry(reg.d[B]).b);
|
2018-08-25 11:38:45 +00:00
|
|
|
break;
|
|
|
|
case CAST_S2So:
|
2018-09-02 13:36:39 +00:00
|
|
|
reg.d[A] = FSoundID(reg.s[B]);
|
2018-08-25 11:38:45 +00:00
|
|
|
break;
|
|
|
|
case CAST_So2S:
|
2018-09-02 13:36:39 +00:00
|
|
|
reg.s[A] = S_sfx[reg.d[B]].name;
|
2018-08-25 11:38:45 +00:00
|
|
|
break;
|
|
|
|
case CAST_SID2S:
|
2018-09-02 13:36:39 +00:00
|
|
|
reg.s[A] = unsigned(reg.d[B]) >= sprites.Size() ? "TNT1" : sprites[reg.d[B]].name;
|
2018-08-25 11:38:45 +00:00
|
|
|
break;
|
|
|
|
case CAST_TID2S:
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto tex = TexMan[*(FTextureID*)&(reg.d[B])];
|
|
|
|
reg.s[A] = tex == nullptr ? "(null)" : tex->Name.GetChars();
|
2018-08-25 11:38:45 +00:00
|
|
|
break;
|
|
|
|
}*/
|
|
|
|
default:
|
|
|
|
assert(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitCASTB()
|
|
|
|
{
|
|
|
|
if (C == CASTB_I)
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(regD[A], regD[B]);
|
|
|
|
cc.shr(regD[A], 31);
|
2018-08-25 11:38:45 +00:00
|
|
|
}
|
|
|
|
else if (C == CASTB_F)
|
|
|
|
{
|
|
|
|
auto zero = cc.newXmm();
|
|
|
|
auto one = cc.newInt32();
|
|
|
|
cc.xorpd(zero, zero);
|
|
|
|
cc.mov(one, 1);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.ucomisd(regF[A], zero);
|
|
|
|
cc.setp(regD[A]);
|
|
|
|
cc.cmovne(regD[A], one);
|
2018-08-25 11:38:45 +00:00
|
|
|
}
|
|
|
|
else if (C == CASTB_A)
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.test(regA[A], regA[A]);
|
|
|
|
cc.setne(regD[A]);
|
2018-08-25 11:38:45 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
//reg.d[A] = reg.s[B].Len() > 0;
|
2018-08-25 11:38:45 +00:00
|
|
|
}
|
|
|
|
}
|
2018-08-19 22:44:48 +00:00
|
|
|
|
|
|
|
void EmitDYNCAST_R()
|
|
|
|
{
|
|
|
|
using namespace asmjit;
|
|
|
|
typedef DObject*(*FuncPtr)(DObject*, PClass*);
|
|
|
|
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(static_cast<FuncPtr>([](DObject *obj, PClass *cls) -> DObject* {
|
|
|
|
return (obj && obj->IsKindOf(cls)) ? obj : nullptr;
|
|
|
|
}))), FuncSignature2<void*, void*, void*>());
|
2018-09-02 13:36:39 +00:00
|
|
|
call->setRet(0, regA[A]);
|
2018-08-19 22:44:48 +00:00
|
|
|
call->setArg(0, regA[B]);
|
|
|
|
call->setArg(1, regA[C]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitDYNCAST_K()
|
|
|
|
{
|
|
|
|
using namespace asmjit;
|
|
|
|
auto c = cc.newIntPtr();
|
|
|
|
cc.mov(c, ToMemAddress(konsta[C].o));
|
|
|
|
typedef DObject*(*FuncPtr)(DObject*, PClass*);
|
|
|
|
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(static_cast<FuncPtr>([](DObject *obj, PClass *cls) -> DObject* {
|
|
|
|
return (obj && obj->IsKindOf(cls)) ? obj : nullptr;
|
|
|
|
}))), FuncSignature2<void*, void*, void*>());
|
2018-09-02 13:36:39 +00:00
|
|
|
call->setRet(0, regA[A]);
|
2018-08-19 22:44:48 +00:00
|
|
|
call->setArg(0, regA[B]);
|
|
|
|
call->setArg(1, c);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitDYNCASTC_R()
|
|
|
|
{
|
|
|
|
using namespace asmjit;
|
|
|
|
typedef PClass*(*FuncPtr)(PClass*, PClass*);
|
|
|
|
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(static_cast<FuncPtr>([](PClass *cls1, PClass *cls2) -> PClass* {
|
|
|
|
return (cls1 && cls1->IsDescendantOf(cls2)) ? cls1 : nullptr;
|
|
|
|
}))), FuncSignature2<void*, void*, void*>());
|
2018-09-02 13:36:39 +00:00
|
|
|
call->setRet(0, regA[A]);
|
2018-08-19 22:44:48 +00:00
|
|
|
call->setArg(0, regA[B]);
|
|
|
|
call->setArg(1, regA[C]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitDYNCASTC_K()
|
|
|
|
{
|
|
|
|
using namespace asmjit;
|
|
|
|
auto c = cc.newIntPtr();
|
|
|
|
cc.mov(c, ToMemAddress(konsta[C].o));
|
|
|
|
typedef PClass*(*FuncPtr)(PClass*, PClass*);
|
|
|
|
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(static_cast<FuncPtr>([](PClass *cls1, PClass *cls2) -> PClass* {
|
|
|
|
return (cls1 && cls1->IsDescendantOf(cls2)) ? cls1 : nullptr;
|
|
|
|
}))), FuncSignature2<void*, void*, void*>());
|
2018-09-02 13:36:39 +00:00
|
|
|
call->setRet(0, regA[A]);
|
2018-08-19 22:44:48 +00:00
|
|
|
call->setArg(0, regA[B]);
|
|
|
|
call->setArg(1, c);
|
|
|
|
}
|
2018-08-18 23:46:56 +00:00
|
|
|
|
|
|
|
// Control flow.
|
|
|
|
|
2018-08-19 22:44:48 +00:00
|
|
|
void EmitTEST()
|
|
|
|
{
|
|
|
|
int i = (int)(ptrdiff_t)(pc - sfunc->Code);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.cmp(regD[A], BC);
|
2018-09-09 20:03:57 +00:00
|
|
|
cc.jne(labels[i + 2]);
|
2018-08-19 22:44:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitTESTN()
|
|
|
|
{
|
|
|
|
int bc = BC;
|
|
|
|
int i = (int)(ptrdiff_t)(pc - sfunc->Code);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.cmp(regD[A], -bc);
|
2018-09-09 20:03:57 +00:00
|
|
|
cc.jne(labels[i + 2]);
|
2018-08-19 22:44:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitJMP()
|
|
|
|
{
|
|
|
|
auto dest = pc + JMPOFS(pc) + 1;
|
|
|
|
int i = (int)(ptrdiff_t)(dest - sfunc->Code);
|
|
|
|
cc.jmp(labels[i]);
|
|
|
|
}
|
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
//void EmitIJMP() {} // pc += dA + BC -- BC is a signed offset. The target instruction must be a JMP.
|
2018-09-11 15:08:51 +00:00
|
|
|
|
|
|
|
void EmitPARAM()
|
|
|
|
{
|
|
|
|
using namespace asmjit;
|
|
|
|
|
|
|
|
int index = NumParam++;
|
2018-09-12 19:58:31 +00:00
|
|
|
ParamOpcodes.Push(pc);
|
2018-09-11 15:08:51 +00:00
|
|
|
|
|
|
|
X86Gp stackPtr, tmp;
|
|
|
|
X86Xmm tmp2;
|
|
|
|
|
|
|
|
switch (B)
|
|
|
|
{
|
|
|
|
case REGT_NIL:
|
|
|
|
cc.mov(x86::ptr(params, index * sizeof(VMValue) + offsetof(VMValue, a)), (int64_t)0);
|
|
|
|
cc.mov(x86::byte_ptr(params, index * sizeof(VMValue) + offsetof(VMValue, Type)), (int)REGT_NIL);
|
|
|
|
break;
|
|
|
|
case REGT_INT:
|
|
|
|
cc.mov(x86::dword_ptr(params, index * sizeof(VMValue) + offsetof(VMValue, i)), regD[C]);
|
|
|
|
cc.mov(x86::byte_ptr(params, index * sizeof(VMValue) + offsetof(VMValue, Type)), (int)REGT_INT);
|
|
|
|
break;
|
|
|
|
case REGT_INT | REGT_ADDROF:
|
|
|
|
stackPtr = cc.newIntPtr();
|
|
|
|
cc.mov(stackPtr, frameD);
|
|
|
|
cc.add(stackPtr, C * sizeof(int32_t));
|
|
|
|
cc.mov(x86::ptr(params, index * sizeof(VMValue) + offsetof(VMValue, a)), stackPtr);
|
|
|
|
cc.mov(x86::byte_ptr(params, index * sizeof(VMValue) + offsetof(VMValue, Type)), (int)REGT_POINTER);
|
|
|
|
break;
|
|
|
|
case REGT_INT | REGT_KONST:
|
|
|
|
cc.mov(x86::dword_ptr(params, index * sizeof(VMValue) + offsetof(VMValue, i)), konstd[C]);
|
|
|
|
cc.mov(x86::byte_ptr(params, index * sizeof(VMValue) + offsetof(VMValue, Type)), (int)REGT_INT);
|
|
|
|
break;
|
|
|
|
//case REGT_STRING:
|
|
|
|
//case REGT_STRING | REGT_ADDROF:
|
|
|
|
//case REGT_STRING | REGT_KONST:
|
|
|
|
case REGT_POINTER:
|
|
|
|
cc.mov(x86::ptr(params, index * sizeof(VMValue) + offsetof(VMValue, a)), regA[C]);
|
|
|
|
cc.mov(x86::byte_ptr(params, index * sizeof(VMValue) + offsetof(VMValue, Type)), (int)REGT_POINTER);
|
|
|
|
break;
|
|
|
|
case REGT_POINTER | REGT_ADDROF:
|
|
|
|
stackPtr = cc.newIntPtr();
|
|
|
|
cc.mov(stackPtr, frameA);
|
|
|
|
cc.add(stackPtr, C * sizeof(void*));
|
|
|
|
cc.mov(x86::ptr(params, index * sizeof(VMValue) + offsetof(VMValue, a)), stackPtr);
|
|
|
|
cc.mov(x86::byte_ptr(params, index * sizeof(VMValue) + offsetof(VMValue, Type)), (int)REGT_POINTER);
|
|
|
|
break;
|
|
|
|
case REGT_POINTER | REGT_KONST:
|
2018-09-12 19:58:31 +00:00
|
|
|
tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, ToMemAddress(konsta[C].v));
|
|
|
|
cc.mov(x86::ptr(params, index * sizeof(VMValue) + offsetof(VMValue, a)), tmp);
|
2018-09-11 15:08:51 +00:00
|
|
|
cc.mov(x86::byte_ptr(params, index * sizeof(VMValue) + offsetof(VMValue, Type)), (int)REGT_POINTER);
|
|
|
|
break;
|
|
|
|
case REGT_FLOAT:
|
|
|
|
cc.movsd(x86::qword_ptr(params, index * sizeof(VMValue) + offsetof(VMValue, f)), regF[C]);
|
|
|
|
cc.mov(x86::byte_ptr(params, index * sizeof(VMValue) + offsetof(VMValue, Type)), (int)REGT_FLOAT);
|
|
|
|
break;
|
|
|
|
case REGT_FLOAT | REGT_MULTIREG2:
|
|
|
|
cc.movsd(x86::qword_ptr(params, index * sizeof(VMValue) + offsetof(VMValue, f)), regF[C]);
|
|
|
|
cc.mov(x86::byte_ptr(params, index * sizeof(VMValue) + offsetof(VMValue, Type)), (int)REGT_FLOAT);
|
|
|
|
index = NumParam++;
|
2018-09-12 19:58:31 +00:00
|
|
|
ParamOpcodes.Push(pc);
|
2018-09-11 15:08:51 +00:00
|
|
|
cc.movsd(x86::qword_ptr(params, index * sizeof(VMValue) + offsetof(VMValue, f)), regF[C + 1]);
|
|
|
|
cc.mov(x86::byte_ptr(params, index * sizeof(VMValue) + offsetof(VMValue, Type)), (int)REGT_FLOAT);
|
|
|
|
break;
|
|
|
|
case REGT_FLOAT | REGT_MULTIREG3:
|
|
|
|
cc.movsd(x86::qword_ptr(params, index * sizeof(VMValue) + offsetof(VMValue, f)), regF[C]);
|
|
|
|
cc.mov(x86::byte_ptr(params, index * sizeof(VMValue) + offsetof(VMValue, Type)), (int)REGT_FLOAT);
|
|
|
|
index = NumParam++;
|
2018-09-12 19:58:31 +00:00
|
|
|
ParamOpcodes.Push(pc);
|
2018-09-11 15:08:51 +00:00
|
|
|
cc.movsd(x86::qword_ptr(params, index * sizeof(VMValue) + offsetof(VMValue, f)), regF[C + 1]);
|
|
|
|
cc.mov(x86::byte_ptr(params, index * sizeof(VMValue) + offsetof(VMValue, Type)), (int)REGT_FLOAT);
|
|
|
|
index = NumParam++;
|
2018-09-12 19:58:31 +00:00
|
|
|
ParamOpcodes.Push(pc);
|
2018-09-11 15:08:51 +00:00
|
|
|
cc.movsd(x86::qword_ptr(params, index * sizeof(VMValue) + offsetof(VMValue, f)), regF[C + 2]);
|
|
|
|
cc.mov(x86::byte_ptr(params, index * sizeof(VMValue) + offsetof(VMValue, Type)), (int)REGT_FLOAT);
|
|
|
|
break;
|
|
|
|
case REGT_FLOAT | REGT_ADDROF:
|
|
|
|
stackPtr = cc.newIntPtr();
|
|
|
|
cc.mov(stackPtr, frameF);
|
|
|
|
cc.add(stackPtr, C * sizeof(double));
|
|
|
|
cc.mov(x86::ptr(params, index * sizeof(VMValue) + offsetof(VMValue, a)), stackPtr);
|
|
|
|
cc.mov(x86::byte_ptr(params, index * sizeof(VMValue) + offsetof(VMValue, Type)), (int)REGT_POINTER);
|
|
|
|
break;
|
|
|
|
case REGT_FLOAT | REGT_KONST:
|
|
|
|
tmp = cc.newIntPtr();
|
|
|
|
tmp2 = cc.newXmmSd();
|
|
|
|
cc.mov(tmp, ToMemAddress(konstf + C));
|
|
|
|
cc.movsd(tmp2, asmjit::x86::qword_ptr(tmp));
|
|
|
|
cc.movsd(x86::qword_ptr(params, index * sizeof(VMValue) + offsetof(VMValue, f)), tmp2);
|
|
|
|
cc.mov(x86::byte_ptr(params, index * sizeof(VMValue) + offsetof(VMValue, Type)), (int)REGT_FLOAT);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
I_FatalError("Unknown REGT value passed to EmitPARAM\n");
|
|
|
|
break;
|
|
|
|
}
|
2018-09-12 19:58:31 +00:00
|
|
|
|
2018-09-11 15:08:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitPARAMI()
|
|
|
|
{
|
|
|
|
int index = NumParam++;
|
2018-09-12 19:58:31 +00:00
|
|
|
ParamOpcodes.Push(pc);
|
2018-09-11 15:08:51 +00:00
|
|
|
cc.mov(asmjit::x86::dword_ptr(params, index * sizeof(VMValue) + offsetof(VMValue, i)), (int)ABCs);
|
|
|
|
cc.mov(asmjit::x86::byte_ptr(params, index * sizeof(VMValue) + offsetof(VMValue, Type)), (int)REGT_INT);
|
|
|
|
}
|
|
|
|
|
2018-09-11 23:37:30 +00:00
|
|
|
void EmitCALL()
|
|
|
|
{
|
|
|
|
EmitDoCall(regA[A]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitCALL_K()
|
|
|
|
{
|
|
|
|
auto ptr = cc.newIntPtr();
|
|
|
|
cc.mov(ptr, ToMemAddress(konsta[A].o));
|
|
|
|
EmitDoCall(ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitDoCall(asmjit::X86Gp ptr)
|
|
|
|
{
|
|
|
|
using namespace asmjit;
|
|
|
|
|
2018-09-12 19:58:31 +00:00
|
|
|
if (NumParam < B)
|
2018-09-11 23:37:30 +00:00
|
|
|
I_FatalError("OP_CALL parameter count does not match the number of preceding OP_PARAM instructions");
|
|
|
|
|
2018-09-12 19:58:31 +00:00
|
|
|
StoreInOuts(B);
|
2018-09-11 23:37:30 +00:00
|
|
|
FillReturns(pc + 1, C);
|
|
|
|
|
2018-09-12 19:58:31 +00:00
|
|
|
X86Gp paramsptr;
|
|
|
|
if (B != NumParam)
|
|
|
|
{
|
|
|
|
paramsptr = cc.newIntPtr();
|
|
|
|
cc.mov(paramsptr, params);
|
|
|
|
cc.add(paramsptr, (NumParam - B) * sizeof(VMValue));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
paramsptr = params;
|
|
|
|
}
|
|
|
|
|
2018-09-11 23:37:30 +00:00
|
|
|
auto result = cc.newInt32();
|
|
|
|
auto call = cc.call(ToMemAddress(&JitCompiler::DoCall), FuncSignature7<int, void*, void*, int, int, void*, void*, void*>());
|
|
|
|
call->setRet(0, result);
|
|
|
|
call->setArg(0, stack);
|
|
|
|
call->setArg(1, ptr);
|
|
|
|
call->setArg(2, asmjit::Imm(B));
|
|
|
|
call->setArg(3, asmjit::Imm(C));
|
2018-09-12 19:58:31 +00:00
|
|
|
call->setArg(4, paramsptr);
|
2018-09-11 23:37:30 +00:00
|
|
|
call->setArg(5, callReturns);
|
|
|
|
call->setArg(6, exceptInfo);
|
|
|
|
|
|
|
|
auto noexception = cc.newLabel();
|
|
|
|
auto exceptResult = cc.newInt32();
|
|
|
|
cc.mov(exceptResult, x86::dword_ptr(exceptInfo, 0 * 4));
|
|
|
|
cc.cmp(exceptResult, (int)-1);
|
|
|
|
cc.je(noexception);
|
|
|
|
X86Gp vReg = cc.newInt32();
|
|
|
|
cc.mov(vReg, 0);
|
|
|
|
cc.ret(vReg);
|
|
|
|
cc.bind(noexception);
|
|
|
|
|
|
|
|
LoadReturns(pc - B, B, true);
|
|
|
|
LoadReturns(pc + 1, C, false);
|
2018-09-12 19:58:31 +00:00
|
|
|
|
|
|
|
NumParam -= B;
|
|
|
|
ParamOpcodes.Resize(ParamOpcodes.Size() - B);
|
2018-09-11 23:37:30 +00:00
|
|
|
}
|
|
|
|
|
2018-09-12 19:58:31 +00:00
|
|
|
void StoreInOuts(int b)
|
2018-09-11 23:37:30 +00:00
|
|
|
{
|
2018-09-12 19:58:31 +00:00
|
|
|
using namespace asmjit;
|
2018-09-11 23:37:30 +00:00
|
|
|
|
2018-09-12 19:58:31 +00:00
|
|
|
for (unsigned int i = ParamOpcodes.Size() - b; i < ParamOpcodes.Size(); i++)
|
2018-09-11 23:37:30 +00:00
|
|
|
{
|
2018-09-12 19:58:31 +00:00
|
|
|
asmjit::X86Gp stackPtr;
|
|
|
|
switch (ParamOpcodes[i]->b)
|
|
|
|
{
|
|
|
|
case REGT_INT | REGT_ADDROF:
|
|
|
|
stackPtr = cc.newIntPtr();
|
|
|
|
cc.mov(stackPtr, frameD);
|
|
|
|
cc.add(stackPtr, C * sizeof(int32_t));
|
|
|
|
cc.mov(x86::dword_ptr(stackPtr), regD[C]);
|
|
|
|
break;
|
|
|
|
//case REGT_STRING | REGT_ADDROF:
|
|
|
|
// break;
|
|
|
|
case REGT_POINTER | REGT_ADDROF:
|
|
|
|
stackPtr = cc.newIntPtr();
|
|
|
|
cc.mov(stackPtr, frameA);
|
|
|
|
cc.add(stackPtr, C * sizeof(void*));
|
|
|
|
cc.mov(x86::ptr(stackPtr), regA[C]);
|
|
|
|
break;
|
|
|
|
case REGT_FLOAT | REGT_ADDROF:
|
|
|
|
stackPtr = cc.newIntPtr();
|
|
|
|
cc.mov(stackPtr, frameF);
|
|
|
|
cc.add(stackPtr, C * sizeof(double));
|
|
|
|
cc.movsd(x86::qword_ptr(stackPtr), regF[C]);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2018-09-11 23:37:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LoadReturns(const VMOP *retval, int numret, bool inout)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < numret; ++i)
|
|
|
|
{
|
|
|
|
if (!inout && retval[i].op != OP_RESULT)
|
|
|
|
I_FatalError("Expected OP_RESULT to follow OP_CALL\n");
|
|
|
|
else if (inout && retval[i].op != OP_PARAMI)
|
|
|
|
continue;
|
|
|
|
else if (inout && retval[i].op != OP_PARAM)
|
|
|
|
I_FatalError("Expected OP_PARAM to precede OP_CALL\n");
|
|
|
|
|
|
|
|
int type = retval[i].b;
|
|
|
|
int regnum = retval[i].c;
|
|
|
|
|
|
|
|
if (inout && !(type & REGT_ADDROF))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
switch (type & REGT_TYPE)
|
|
|
|
{
|
|
|
|
case REGT_INT:
|
|
|
|
cc.mov(regD[regnum], asmjit::x86::dword_ptr(frameD, regnum * sizeof(int32_t)));
|
|
|
|
break;
|
|
|
|
case REGT_FLOAT:
|
|
|
|
cc.movsd(regF[regnum], asmjit::x86::qword_ptr(frameF, regnum * sizeof(double)));
|
|
|
|
break;
|
|
|
|
/*case REGT_STRING:
|
|
|
|
break;*/
|
|
|
|
case REGT_POINTER:
|
|
|
|
cc.mov(regA[regnum], asmjit::x86::ptr(frameA, regnum * sizeof(void*)));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
I_FatalError("Unknown OP_RESULT type encountered in LoadReturns\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FillReturns(const VMOP *retval, int numret)
|
|
|
|
{
|
|
|
|
using namespace asmjit;
|
|
|
|
|
|
|
|
for (int i = 0; i < numret; ++i)
|
|
|
|
{
|
|
|
|
if (retval[i].op != OP_RESULT)
|
|
|
|
{
|
|
|
|
I_FatalError("Expected OP_RESULT to follow OP_CALL\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
int type = retval[i].b;
|
|
|
|
int regnum = retval[i].c;
|
|
|
|
|
|
|
|
if (type & REGT_KONST)
|
|
|
|
{
|
|
|
|
I_FatalError("OP_RESULT with REGT_KONST is not allowed\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
auto regPtr = cc.newIntPtr();
|
|
|
|
|
|
|
|
switch (type & REGT_TYPE)
|
|
|
|
{
|
|
|
|
case REGT_INT:
|
|
|
|
cc.mov(regPtr, frameD);
|
|
|
|
cc.add(regPtr, regnum * sizeof(int32_t));
|
|
|
|
break;
|
|
|
|
case REGT_FLOAT:
|
|
|
|
cc.mov(regPtr, frameF);
|
|
|
|
cc.add(regPtr, regnum * sizeof(double));
|
|
|
|
break;
|
|
|
|
/*case REGT_STRING:
|
|
|
|
cc.mov(regPtr, frameS);
|
|
|
|
cc.add(regPtr, regnum * sizeof(FString));
|
|
|
|
break;*/
|
|
|
|
case REGT_POINTER:
|
|
|
|
cc.mov(regPtr, frameA);
|
|
|
|
cc.add(regPtr, regnum * sizeof(void*));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
I_FatalError("Unknown OP_RESULT type encountered in FillReturns\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
cc.mov(x86::ptr(callReturns, i * sizeof(VMReturn) + offsetof(VMReturn, Location)), regPtr);
|
|
|
|
cc.mov(x86::byte_ptr(callReturns, i * sizeof(VMReturn) + offsetof(VMReturn, RegType)), type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int DoCall(VMFrameStack *stack, VMFunction *call, int b, int c, VMValue *param, VMReturn *returns, JitExceptionInfo *exceptinfo)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
int numret;
|
|
|
|
if (call->VarFlags & VARF_Native)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
VMCycles[0].Unclock();
|
|
|
|
numret = static_cast<VMNativeFunction *>(call)->NativeCall(param, call->DefaultArgs, b, returns, c);
|
|
|
|
VMCycles[0].Clock();
|
|
|
|
}
|
|
|
|
catch (CVMAbortException &err)
|
|
|
|
{
|
|
|
|
err.MaybePrintMessage();
|
|
|
|
err.stacktrace.AppendFormat("Called from %s\n", call->PrintableName.GetChars());
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
VMCalls[0]++;
|
|
|
|
VMScriptFunction *script = static_cast<VMScriptFunction *>(call);
|
|
|
|
VMFrame *newf = stack->AllocFrame(script);
|
|
|
|
VMFillParams(param, newf, b);
|
|
|
|
try
|
|
|
|
{
|
|
|
|
numret = VMExec(stack, script->Code, returns, c);
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
stack->PopFrame();
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
stack->PopFrame();
|
|
|
|
}
|
|
|
|
|
|
|
|
return numret;
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
// To do: store full exception in exceptinfo
|
|
|
|
exceptinfo->reason = X_OTHER;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2018-09-02 01:39:02 +00:00
|
|
|
|
|
|
|
void EmitVTBL()
|
|
|
|
{
|
|
|
|
auto notnull = cc.newLabel();
|
|
|
|
cc.test(regA[B], regA[B]);
|
|
|
|
cc.jnz(notnull);
|
|
|
|
EmitThrowException(X_READ_NIL);
|
|
|
|
cc.bind(notnull);
|
|
|
|
|
|
|
|
auto result = cc.newInt32();
|
|
|
|
typedef VMFunction*(*FuncPtr)(DObject*, int);
|
|
|
|
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(static_cast<FuncPtr>([](DObject *o, int c) -> VMFunction* {
|
|
|
|
auto p = o->GetClass();
|
|
|
|
assert(c < (int)p->Virtuals.Size());
|
|
|
|
return p->Virtuals[c];
|
|
|
|
}))), asmjit::FuncSignature2<void*, void*, int>());
|
|
|
|
call->setRet(0, result);
|
2018-09-02 13:36:39 +00:00
|
|
|
call->setArg(0, regA[A]);
|
2018-09-02 01:39:02 +00:00
|
|
|
call->setArg(1, asmjit::Imm(C));
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSCOPE()
|
|
|
|
{
|
|
|
|
auto notnull = cc.newLabel();
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.test(regA[A], regA[A]);
|
2018-09-02 01:39:02 +00:00
|
|
|
cc.jnz(notnull);
|
|
|
|
EmitThrowException(X_READ_NIL);
|
|
|
|
cc.bind(notnull);
|
|
|
|
|
|
|
|
auto f = cc.newIntPtr();
|
|
|
|
cc.mov(f, ToMemAddress(konsta[C].v));
|
|
|
|
|
|
|
|
auto result = cc.newInt32();
|
|
|
|
typedef int(*FuncPtr)(DObject*, VMFunction*, int);
|
|
|
|
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(static_cast<FuncPtr>([](DObject *o, VMFunction *f, int b) -> int {
|
|
|
|
try
|
|
|
|
{
|
|
|
|
FScopeBarrier::ValidateCall(o->GetClass(), f, b - 1);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
catch (const CVMAbortException &)
|
|
|
|
{
|
|
|
|
// To do: pass along the exception info
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}))), asmjit::FuncSignature3<int, void*, void*, int>());
|
|
|
|
call->setRet(0, result);
|
2018-09-02 13:36:39 +00:00
|
|
|
call->setArg(0, regA[A]);
|
2018-09-02 01:39:02 +00:00
|
|
|
call->setArg(1, f);
|
|
|
|
call->setArg(2, asmjit::Imm(B));
|
|
|
|
|
|
|
|
auto notzero = cc.newLabel();
|
|
|
|
cc.test(result, result);
|
|
|
|
cc.jnz(notzero);
|
|
|
|
EmitThrowException(X_OTHER);
|
|
|
|
cc.bind(notzero);
|
|
|
|
}
|
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
//void EmitTAIL() {} // Call+Ret in a single instruction
|
|
|
|
//void EmitTAIL_K() {}
|
2018-08-19 23:40:37 +00:00
|
|
|
|
|
|
|
void EmitRESULT()
|
|
|
|
{
|
|
|
|
// This instruction is just a placeholder to indicate where a return
|
|
|
|
// value should be stored. It does nothing on its own and should not
|
|
|
|
// be executed.
|
|
|
|
}
|
2018-08-18 23:46:56 +00:00
|
|
|
|
|
|
|
void EmitRET()
|
|
|
|
{
|
|
|
|
using namespace asmjit;
|
|
|
|
if (B == REGT_NIL)
|
|
|
|
{
|
|
|
|
X86Gp vReg = cc.newInt32();
|
|
|
|
cc.mov(vReg, 0);
|
|
|
|
cc.ret(vReg);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
int a = A;
|
2018-08-18 23:46:56 +00:00
|
|
|
int retnum = a & ~RET_FINAL;
|
|
|
|
|
|
|
|
X86Gp reg_retnum = cc.newInt32();
|
|
|
|
X86Gp location = cc.newIntPtr();
|
|
|
|
Label L_endif = cc.newLabel();
|
|
|
|
|
|
|
|
cc.mov(reg_retnum, retnum);
|
|
|
|
cc.test(reg_retnum, numret);
|
|
|
|
cc.jg(L_endif);
|
|
|
|
|
|
|
|
cc.mov(location, x86::ptr(ret, retnum * sizeof(VMReturn)));
|
|
|
|
|
|
|
|
int regtype = B;
|
|
|
|
int regnum = C;
|
|
|
|
switch (regtype & REGT_TYPE)
|
|
|
|
{
|
|
|
|
case REGT_INT:
|
|
|
|
if (regtype & REGT_KONST)
|
|
|
|
cc.mov(x86::dword_ptr(location), konstd[regnum]);
|
|
|
|
else
|
|
|
|
cc.mov(x86::dword_ptr(location), regD[regnum]);
|
2018-08-13 16:07:36 +00:00
|
|
|
break;
|
2018-08-18 23:46:56 +00:00
|
|
|
case REGT_FLOAT:
|
|
|
|
if (regtype & REGT_KONST)
|
2018-08-13 16:07:36 +00:00
|
|
|
{
|
2018-08-18 23:46:56 +00:00
|
|
|
auto tmp = cc.newInt64();
|
|
|
|
if (regtype & REGT_MULTIREG3)
|
|
|
|
{
|
|
|
|
cc.mov(tmp, (((int64_t *)konstf)[regnum]));
|
|
|
|
cc.mov(x86::qword_ptr(location), tmp);
|
|
|
|
|
|
|
|
cc.mov(tmp, (((int64_t *)konstf)[regnum + 1]));
|
|
|
|
cc.mov(x86::qword_ptr(location, 8), tmp);
|
|
|
|
|
|
|
|
cc.mov(tmp, (((int64_t *)konstf)[regnum + 2]));
|
|
|
|
cc.mov(x86::qword_ptr(location, 16), tmp);
|
|
|
|
}
|
|
|
|
else if (regtype & REGT_MULTIREG2)
|
|
|
|
{
|
|
|
|
cc.mov(tmp, (((int64_t *)konstf)[regnum]));
|
|
|
|
cc.mov(x86::qword_ptr(location), tmp);
|
|
|
|
|
|
|
|
cc.mov(tmp, (((int64_t *)konstf)[regnum + 1]));
|
|
|
|
cc.mov(x86::qword_ptr(location, 8), tmp);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cc.mov(tmp, (((int64_t *)konstf)[regnum]));
|
|
|
|
cc.mov(x86::qword_ptr(location), tmp);
|
|
|
|
}
|
2018-08-13 16:07:36 +00:00
|
|
|
}
|
2018-08-18 23:46:56 +00:00
|
|
|
else
|
2018-08-13 16:07:36 +00:00
|
|
|
{
|
2018-08-18 23:46:56 +00:00
|
|
|
if (regtype & REGT_MULTIREG3)
|
|
|
|
{
|
|
|
|
cc.movsd(x86::qword_ptr(location), regF[regnum]);
|
|
|
|
cc.movsd(x86::qword_ptr(location, 8), regF[regnum + 1]);
|
|
|
|
cc.movsd(x86::qword_ptr(location, 16), regF[regnum + 2]);
|
|
|
|
}
|
|
|
|
else if (regtype & REGT_MULTIREG2)
|
|
|
|
{
|
|
|
|
cc.movsd(x86::qword_ptr(location), regF[regnum]);
|
|
|
|
cc.movsd(x86::qword_ptr(location, 8), regF[regnum + 1]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cc.movsd(x86::qword_ptr(location), regF[regnum]);
|
|
|
|
}
|
2018-08-13 16:07:36 +00:00
|
|
|
}
|
|
|
|
break;
|
2018-08-18 23:46:56 +00:00
|
|
|
case REGT_STRING:
|
2018-08-25 11:38:45 +00:00
|
|
|
break;
|
2018-08-18 23:46:56 +00:00
|
|
|
case REGT_POINTER:
|
2018-08-25 11:38:45 +00:00
|
|
|
#ifdef ASMJIT_ARCH_X64
|
|
|
|
if (regtype & REGT_KONST)
|
|
|
|
cc.mov(x86::qword_ptr(location), ToMemAddress(konsta[regnum].v));
|
|
|
|
else
|
|
|
|
cc.mov(x86::qword_ptr(location), regA[regnum]);
|
|
|
|
#else
|
|
|
|
if (regtype & REGT_KONST)
|
|
|
|
cc.mov(x86::dword_ptr(location), ToMemAddress(konsta[regnum].v));
|
|
|
|
else
|
|
|
|
cc.mov(x86::dword_ptr(location), regA[regnum]);
|
|
|
|
#endif
|
2018-08-13 16:07:36 +00:00
|
|
|
break;
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (a & RET_FINAL)
|
|
|
|
{
|
|
|
|
cc.add(reg_retnum, 1);
|
|
|
|
cc.ret(reg_retnum);
|
|
|
|
}
|
|
|
|
|
|
|
|
cc.bind(L_endif);
|
|
|
|
if (a & RET_FINAL)
|
|
|
|
cc.ret(numret);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitRETI()
|
|
|
|
{
|
|
|
|
using namespace asmjit;
|
|
|
|
|
2018-09-02 13:36:39 +00:00
|
|
|
int a = A;
|
2018-08-18 23:46:56 +00:00
|
|
|
int retnum = a & ~RET_FINAL;
|
|
|
|
|
|
|
|
X86Gp reg_retnum = cc.newInt32();
|
|
|
|
X86Gp location = cc.newIntPtr();
|
|
|
|
Label L_endif = cc.newLabel();
|
|
|
|
|
|
|
|
cc.mov(reg_retnum, retnum);
|
|
|
|
cc.test(reg_retnum, numret);
|
|
|
|
cc.jg(L_endif);
|
|
|
|
|
|
|
|
cc.mov(location, x86::ptr(ret, retnum * sizeof(VMReturn)));
|
|
|
|
cc.mov(x86::dword_ptr(location), BCs);
|
|
|
|
|
|
|
|
if (a & RET_FINAL)
|
|
|
|
{
|
|
|
|
cc.add(reg_retnum, 1);
|
|
|
|
cc.ret(reg_retnum);
|
|
|
|
}
|
|
|
|
|
|
|
|
cc.bind(L_endif);
|
|
|
|
if (a & RET_FINAL)
|
|
|
|
cc.ret(numret);
|
|
|
|
}
|
|
|
|
|
2018-09-02 01:39:02 +00:00
|
|
|
void EmitNEW()
|
|
|
|
{
|
|
|
|
auto result = cc.newIntPtr();
|
|
|
|
typedef DObject*(*FuncPtr)(PClass*, int);
|
|
|
|
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(static_cast<FuncPtr>([](PClass *cls, int c) -> DObject* {
|
|
|
|
try
|
|
|
|
{
|
|
|
|
if (!cls->ConstructNative)
|
|
|
|
{
|
|
|
|
ThrowAbortException(X_OTHER, "Class %s requires native construction", cls->TypeName.GetChars());
|
|
|
|
}
|
|
|
|
else if (cls->bAbstract)
|
|
|
|
{
|
|
|
|
ThrowAbortException(X_OTHER, "Cannot instantiate abstract class %s", cls->TypeName.GetChars());
|
|
|
|
}
|
|
|
|
else if (cls->IsDescendantOf(NAME_Actor)) // Creating actors here must be outright prohibited
|
|
|
|
{
|
|
|
|
ThrowAbortException(X_OTHER, "Cannot create actors with 'new'");
|
|
|
|
}
|
|
|
|
|
|
|
|
// [ZZ] validate readonly and between scope construction
|
|
|
|
if (c) FScopeBarrier::ValidateNew(cls, c - 1);
|
|
|
|
return cls->CreateNew();
|
|
|
|
}
|
|
|
|
catch (const CVMAbortException &)
|
|
|
|
{
|
|
|
|
// To do: pass along the exception info
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}))), asmjit::FuncSignature2<void*, void*, int>());
|
|
|
|
call->setRet(0, result);
|
|
|
|
call->setArg(0, regA[B]);
|
|
|
|
call->setArg(1, asmjit::Imm(C));
|
|
|
|
|
|
|
|
auto notnull = cc.newLabel();
|
|
|
|
cc.test(result, result);
|
|
|
|
cc.jnz(notnull);
|
|
|
|
EmitThrowException(X_OTHER);
|
|
|
|
cc.bind(notnull);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(regA[A], result);
|
2018-09-02 01:39:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitNEW_K()
|
|
|
|
{
|
|
|
|
PClass *cls = (PClass*)konsta[B].v;
|
|
|
|
if (!cls->ConstructNative)
|
|
|
|
{
|
|
|
|
EmitThrowException(X_OTHER); // "Class %s requires native construction", cls->TypeName.GetChars()
|
|
|
|
}
|
|
|
|
else if (cls->bAbstract)
|
|
|
|
{
|
|
|
|
EmitThrowException(X_OTHER); // "Cannot instantiate abstract class %s", cls->TypeName.GetChars()
|
|
|
|
}
|
|
|
|
else if (cls->IsDescendantOf(NAME_Actor)) // Creating actors here must be outright prohibited
|
|
|
|
{
|
|
|
|
EmitThrowException(X_OTHER); // "Cannot create actors with 'new'"
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
auto result = cc.newIntPtr();
|
|
|
|
auto regcls = cc.newIntPtr();
|
|
|
|
cc.mov(regcls, ToMemAddress(konsta[B].v));
|
|
|
|
typedef DObject*(*FuncPtr)(PClass*, int);
|
|
|
|
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(static_cast<FuncPtr>([](PClass *cls, int c) -> DObject* {
|
|
|
|
try
|
|
|
|
{
|
|
|
|
if (c) FScopeBarrier::ValidateNew(cls, c - 1);
|
|
|
|
return cls->CreateNew();
|
|
|
|
}
|
|
|
|
catch (const CVMAbortException &)
|
|
|
|
{
|
|
|
|
// To do: pass along the exception info
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}))), asmjit::FuncSignature2<void*, void*, int>());
|
|
|
|
call->setRet(0, result);
|
|
|
|
call->setArg(0, regcls);
|
|
|
|
call->setArg(1, asmjit::Imm(C));
|
|
|
|
|
|
|
|
auto notnull = cc.newLabel();
|
|
|
|
cc.test(result, result);
|
|
|
|
cc.jnz(notnull);
|
|
|
|
EmitThrowException(X_OTHER);
|
|
|
|
cc.bind(notnull);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(regA[A], result);
|
2018-09-02 01:39:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitTHROW()
|
|
|
|
{
|
|
|
|
EmitThrowException(EVMAbortException(BC));
|
|
|
|
}
|
2018-08-26 12:27:46 +00:00
|
|
|
|
|
|
|
void EmitBOUND()
|
|
|
|
{
|
|
|
|
auto label1 = cc.newLabel();
|
|
|
|
auto label2 = cc.newLabel();
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.cmp(regD[A], (int)BC);
|
2018-08-26 12:27:46 +00:00
|
|
|
cc.jl(label1);
|
2018-09-02 13:36:39 +00:00
|
|
|
EmitThrowException(X_ARRAY_OUT_OF_BOUNDS); // "Max.index = %u, current index = %u\n", BC, reg.d[A]
|
2018-08-26 12:27:46 +00:00
|
|
|
cc.bind(label1);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.cmp(regD[A], (int)0);
|
2018-08-26 12:27:46 +00:00
|
|
|
cc.jge(label2);
|
2018-09-02 13:36:39 +00:00
|
|
|
EmitThrowException(X_ARRAY_OUT_OF_BOUNDS); // "Negative current index = %i\n", reg.d[A]
|
2018-08-26 12:27:46 +00:00
|
|
|
cc.bind(label2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitBOUND_K()
|
|
|
|
{
|
|
|
|
auto label1 = cc.newLabel();
|
|
|
|
auto label2 = cc.newLabel();
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.cmp(regD[A], (int)konstd[BC]);
|
2018-08-26 12:27:46 +00:00
|
|
|
cc.jl(label1);
|
2018-09-02 13:36:39 +00:00
|
|
|
EmitThrowException(X_ARRAY_OUT_OF_BOUNDS); // "Max.index = %u, current index = %u\n", konstd[BC], reg.d[A]
|
2018-08-26 12:27:46 +00:00
|
|
|
cc.bind(label1);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.cmp(regD[A], (int)0);
|
2018-08-26 12:27:46 +00:00
|
|
|
cc.jge(label2);
|
2018-09-02 13:36:39 +00:00
|
|
|
EmitThrowException(X_ARRAY_OUT_OF_BOUNDS); // "Negative current index = %i\n", reg.d[A]
|
2018-08-26 12:27:46 +00:00
|
|
|
cc.bind(label2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitBOUND_R()
|
|
|
|
{
|
|
|
|
auto label1 = cc.newLabel();
|
|
|
|
auto label2 = cc.newLabel();
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.cmp(regD[A], regD[B]);
|
2018-08-26 12:27:46 +00:00
|
|
|
cc.jl(label1);
|
2018-09-02 13:36:39 +00:00
|
|
|
EmitThrowException(X_ARRAY_OUT_OF_BOUNDS); // "Max.index = %u, current index = %u\n", reg.d[B], reg.d[A]
|
2018-08-26 12:27:46 +00:00
|
|
|
cc.bind(label1);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.cmp(regD[A], (int)0);
|
2018-08-26 12:27:46 +00:00
|
|
|
cc.jge(label2);
|
2018-09-02 13:36:39 +00:00
|
|
|
EmitThrowException(X_ARRAY_OUT_OF_BOUNDS); // "Negative current index = %i\n", reg.d[A]
|
2018-08-26 12:27:46 +00:00
|
|
|
cc.bind(label2);
|
|
|
|
}
|
2018-08-18 23:46:56 +00:00
|
|
|
|
|
|
|
// String instructions.
|
|
|
|
|
|
|
|
//void EmitCONCAT() {} // sA = sB..sC
|
|
|
|
//void EmitLENS() {} // dA = sB.Length
|
|
|
|
//void EmitCMPS() {} // if ((skB op skC) != (A & 1)) then pc++
|
|
|
|
|
|
|
|
// Integer math.
|
|
|
|
|
|
|
|
void EmitSLL_RR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc = CheckRegD(C, A);
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.mov(regD[A], regD[B]);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.shl(regD[A], rc);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSLL_RI()
|
|
|
|
{
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.mov(regD[A], regD[B]);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.shl(regD[A], C);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSLL_KR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc = CheckRegD(C, A);
|
|
|
|
cc.mov(regD[A], konstd[B]);
|
|
|
|
cc.shl(regD[A], rc);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSRL_RR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc = CheckRegD(C, A);
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.mov(regD[A], regD[B]);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.shr(regD[A], rc);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSRL_RI()
|
|
|
|
{
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.mov(regD[A], regD[B]);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.shr(regD[A], C);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSRL_KR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc = CheckRegD(C, A);
|
|
|
|
cc.mov(regD[A], konstd[B]);
|
|
|
|
cc.shr(regD[A], rc);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSRA_RR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc = CheckRegD(C, A);
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.mov(regD[A], regD[B]);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.sar(regD[A], rc);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSRA_RI()
|
|
|
|
{
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.mov(regD[A], regD[B]);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.sar(regD[A], C);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSRA_KR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc = CheckRegD(C, A);
|
|
|
|
cc.mov(regD[A], konstd[B]);
|
|
|
|
cc.sar(regD[A], rc);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitADD_RR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc = CheckRegD(C, A);
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.mov(regD[A], regD[B]);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.add(regD[A], rc);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitADD_RK()
|
|
|
|
{
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.mov(regD[A], regD[B]);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.add(regD[A], konstd[C]);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitADDI()
|
|
|
|
{
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.mov(regD[A], regD[B]);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.add(regD[A], Cs);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSUB_RR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc = CheckRegD(C, A);
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.mov(regD[A], regD[B]);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.sub(regD[A], rc);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSUB_RK()
|
|
|
|
{
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.mov(regD[A], regD[B]);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.sub(regD[A], konstd[C]);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSUB_KR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc = CheckRegD(C, A);
|
|
|
|
cc.mov(regD[A], konstd[B]);
|
|
|
|
cc.sub(regD[A], rc);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitMUL_RR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc = CheckRegD(C, A);
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.mov(regD[A], regD[B]);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.imul(regD[A], rc);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitMUL_RK()
|
|
|
|
{
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.mov(regD[A], regD[B]);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.imul(regD[A], konstd[C]);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitDIV_RR()
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newInt32();
|
|
|
|
auto tmp1 = cc.newInt32();
|
|
|
|
auto label = cc.newLabel();
|
|
|
|
|
2018-08-25 11:38:45 +00:00
|
|
|
cc.test(regD[C], regD[C]);
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.jne(label);
|
|
|
|
|
|
|
|
EmitThrowException(X_DIVISION_BY_ZERO);
|
|
|
|
|
|
|
|
cc.bind(label);
|
|
|
|
cc.mov(tmp0, regD[B]);
|
|
|
|
cc.cdq(tmp1, tmp0);
|
|
|
|
cc.idiv(tmp1, tmp0, regD[C]);
|
|
|
|
cc.mov(regD[A], tmp0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitDIV_RK()
|
|
|
|
{
|
|
|
|
if (konstd[C] != 0)
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newInt32();
|
|
|
|
auto tmp1 = cc.newInt32();
|
|
|
|
auto konstTmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp0, regD[B]);
|
|
|
|
cc.cdq(tmp1, tmp0);
|
|
|
|
cc.mov(konstTmp, ToMemAddress(&konstd[C]));
|
|
|
|
cc.idiv(tmp1, tmp0, asmjit::x86::ptr(konstTmp));
|
|
|
|
cc.mov(regD[A], tmp0);
|
|
|
|
}
|
|
|
|
else EmitThrowException(X_DIVISION_BY_ZERO);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitDIV_KR()
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newInt32();
|
|
|
|
auto tmp1 = cc.newInt32();
|
|
|
|
auto label = cc.newLabel();
|
|
|
|
|
2018-08-25 11:38:45 +00:00
|
|
|
cc.test(regD[C], regD[C]);
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.jne(label);
|
|
|
|
|
|
|
|
EmitThrowException(X_DIVISION_BY_ZERO);
|
|
|
|
|
|
|
|
cc.bind(label);
|
|
|
|
cc.mov(tmp0, konstd[B]);
|
|
|
|
cc.cdq(tmp1, tmp0);
|
|
|
|
cc.idiv(tmp1, tmp0, regD[C]);
|
|
|
|
cc.mov(regD[A], tmp0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitDIVU_RR()
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newInt32();
|
|
|
|
auto tmp1 = cc.newInt32();
|
|
|
|
auto label = cc.newLabel();
|
|
|
|
|
2018-08-25 11:38:45 +00:00
|
|
|
cc.test(regD[C], regD[C]);
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.jne(label);
|
|
|
|
|
|
|
|
EmitThrowException(X_DIVISION_BY_ZERO);
|
|
|
|
|
|
|
|
cc.bind(label);
|
|
|
|
cc.mov(tmp0, regD[B]);
|
|
|
|
cc.mov(tmp1, 0);
|
|
|
|
cc.div(tmp1, tmp0, regD[C]);
|
|
|
|
cc.mov(regD[A], tmp0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitDIVU_RK()
|
|
|
|
{
|
|
|
|
if (konstd[C] != 0)
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newInt32();
|
|
|
|
auto tmp1 = cc.newInt32();
|
|
|
|
auto konstTmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp0, regD[B]);
|
|
|
|
cc.mov(tmp1, 0);
|
|
|
|
cc.mov(konstTmp, ToMemAddress(&konstd[C]));
|
|
|
|
cc.div(tmp1, tmp0, asmjit::x86::ptr(konstTmp));
|
|
|
|
cc.mov(regD[A], tmp0);
|
|
|
|
}
|
|
|
|
else EmitThrowException(X_DIVISION_BY_ZERO);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitDIVU_KR()
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newInt32();
|
|
|
|
auto tmp1 = cc.newInt32();
|
|
|
|
auto label = cc.newLabel();
|
|
|
|
|
2018-08-25 11:38:45 +00:00
|
|
|
cc.test(regD[C], regD[C]);
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.jne(label);
|
|
|
|
|
|
|
|
EmitThrowException(X_DIVISION_BY_ZERO);
|
|
|
|
|
|
|
|
cc.bind(label);
|
|
|
|
cc.mov(tmp0, konstd[B]);
|
|
|
|
cc.mov(tmp1, 0);
|
|
|
|
cc.div(tmp1, tmp0, regD[C]);
|
|
|
|
cc.mov(regD[A], tmp0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitMOD_RR()
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newInt32();
|
|
|
|
auto tmp1 = cc.newInt32();
|
|
|
|
auto label = cc.newLabel();
|
|
|
|
|
2018-08-25 11:38:45 +00:00
|
|
|
cc.test(regD[C], regD[C]);
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.jne(label);
|
|
|
|
|
|
|
|
EmitThrowException(X_DIVISION_BY_ZERO);
|
|
|
|
|
|
|
|
cc.bind(label);
|
|
|
|
cc.mov(tmp0, regD[B]);
|
|
|
|
cc.cdq(tmp1, tmp0);
|
|
|
|
cc.idiv(tmp1, tmp0, regD[C]);
|
|
|
|
cc.mov(regD[A], tmp1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitMOD_RK()
|
|
|
|
{
|
|
|
|
if (konstd[C] != 0)
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newInt32();
|
|
|
|
auto tmp1 = cc.newInt32();
|
|
|
|
auto konstTmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp0, regD[B]);
|
|
|
|
cc.cdq(tmp1, tmp0);
|
|
|
|
cc.mov(konstTmp, ToMemAddress(&konstd[C]));
|
|
|
|
cc.idiv(tmp1, tmp0, asmjit::x86::ptr(konstTmp));
|
|
|
|
cc.mov(regD[A], tmp1);
|
|
|
|
}
|
|
|
|
else EmitThrowException(X_DIVISION_BY_ZERO);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitMOD_KR()
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newInt32();
|
|
|
|
auto tmp1 = cc.newInt32();
|
|
|
|
auto label = cc.newLabel();
|
|
|
|
|
2018-08-25 11:38:45 +00:00
|
|
|
cc.test(regD[C], regD[C]);
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.jne(label);
|
|
|
|
|
|
|
|
EmitThrowException(X_DIVISION_BY_ZERO);
|
|
|
|
|
|
|
|
cc.bind(label);
|
|
|
|
cc.mov(tmp0, konstd[B]);
|
|
|
|
cc.cdq(tmp1, tmp0);
|
|
|
|
cc.idiv(tmp1, tmp0, regD[C]);
|
|
|
|
cc.mov(regD[A], tmp1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitMODU_RR()
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newInt32();
|
|
|
|
auto tmp1 = cc.newInt32();
|
|
|
|
auto label = cc.newLabel();
|
|
|
|
|
2018-08-25 11:38:45 +00:00
|
|
|
cc.test(regD[C], regD[C]);
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.jne(label);
|
|
|
|
|
|
|
|
EmitThrowException(X_DIVISION_BY_ZERO);
|
|
|
|
|
|
|
|
cc.bind(label);
|
|
|
|
cc.mov(tmp0, regD[B]);
|
|
|
|
cc.mov(tmp1, 0);
|
|
|
|
cc.div(tmp1, tmp0, regD[C]);
|
|
|
|
cc.mov(regD[A], tmp1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitMODU_RK()
|
|
|
|
{
|
|
|
|
if (konstd[C] != 0)
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newInt32();
|
|
|
|
auto tmp1 = cc.newInt32();
|
|
|
|
auto konstTmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp0, regD[B]);
|
|
|
|
cc.mov(tmp1, 0);
|
|
|
|
cc.mov(konstTmp, ToMemAddress(&konstd[C]));
|
|
|
|
cc.div(tmp1, tmp0, asmjit::x86::ptr(konstTmp));
|
|
|
|
cc.mov(regD[A], tmp1);
|
|
|
|
}
|
|
|
|
else EmitThrowException(X_DIVISION_BY_ZERO);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitMODU_KR()
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newInt32();
|
|
|
|
auto tmp1 = cc.newInt32();
|
|
|
|
auto label = cc.newLabel();
|
|
|
|
|
2018-08-25 11:38:45 +00:00
|
|
|
cc.test(regD[C], regD[C]);
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.jne(label);
|
|
|
|
|
|
|
|
EmitThrowException(X_DIVISION_BY_ZERO);
|
|
|
|
|
|
|
|
cc.bind(label);
|
|
|
|
cc.mov(tmp0, konstd[B]);
|
|
|
|
cc.mov(tmp1, 0);
|
|
|
|
cc.div(tmp1, tmp0, regD[C]);
|
|
|
|
cc.mov(regD[A], tmp1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitAND_RR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc = CheckRegD(C, A);
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.mov(regD[A], regD[B]);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.and_(regD[A], rc);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitAND_RK()
|
|
|
|
{
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.mov(regD[A], regD[B]);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.and_(regD[A], konstd[C]);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitOR_RR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc = CheckRegD(C, A);
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.mov(regD[A], regD[B]);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.or_(regD[A], rc);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitOR_RK()
|
|
|
|
{
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.mov(regD[A], regD[B]);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.or_(regD[A], konstd[C]);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitXOR_RR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc = CheckRegD(C, A);
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.mov(regD[A], regD[B]);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.xor_(regD[A], rc);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitXOR_RK()
|
|
|
|
{
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.mov(regD[A], regD[B]);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.xor_(regD[A], konstd[C]);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitMIN_RR()
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newXmmSs();
|
|
|
|
auto tmp1 = cc.newXmmSs();
|
|
|
|
cc.movd(tmp0, regD[B]);
|
|
|
|
cc.movd(tmp1, regD[C]);
|
|
|
|
cc.pminsd(tmp0, tmp1);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movd(regD[A], tmp0);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitMIN_RK()
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newXmmSs();
|
|
|
|
auto tmp1 = cc.newXmmSs();
|
|
|
|
auto konstTmp = cc.newIntPtr();
|
|
|
|
cc.mov(konstTmp, ToMemAddress(&konstd[C]));
|
|
|
|
cc.movd(tmp0, regD[B]);
|
|
|
|
cc.movss(tmp1, asmjit::x86::dword_ptr(konstTmp));
|
|
|
|
cc.pminsd(tmp0, tmp1);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movd(regD[A], tmp0);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitMAX_RR()
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newXmmSs();
|
|
|
|
auto tmp1 = cc.newXmmSs();
|
|
|
|
cc.movd(tmp0, regD[B]);
|
|
|
|
cc.movd(tmp1, regD[C]);
|
|
|
|
cc.pmaxsd(tmp0, tmp1);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movd(regD[A], tmp0);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitMAX_RK()
|
|
|
|
{
|
|
|
|
auto tmp0 = cc.newXmmSs();
|
|
|
|
auto tmp1 = cc.newXmmSs();
|
|
|
|
auto konstTmp = cc.newIntPtr();
|
|
|
|
cc.mov(konstTmp, ToMemAddress(&konstd[C]));
|
|
|
|
cc.movd(tmp0, regD[B]);
|
|
|
|
cc.movss(tmp1, asmjit::x86::dword_ptr(konstTmp));
|
|
|
|
cc.pmaxsd(tmp0, tmp1);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movd(regD[A], tmp0);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitABS()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto srcB = CheckRegD(B, A);
|
2018-08-18 23:46:56 +00:00
|
|
|
auto tmp = cc.newInt32();
|
|
|
|
cc.mov(tmp, regD[B]);
|
|
|
|
cc.sar(tmp, 31);
|
|
|
|
cc.mov(regD[A], tmp);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.xor_(regD[A], srcB);
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.sub(regD[A], tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitNEG()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto srcB = CheckRegD(B, A);
|
|
|
|
cc.xor_(regD[A], regD[A]);
|
|
|
|
cc.sub(regD[A], srcB);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitNOT()
|
|
|
|
{
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.mov(regD[A], regD[B]);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.not_(regD[A]);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitEQ_R()
|
|
|
|
{
|
2018-09-11 20:48:02 +00:00
|
|
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.cmp(regD[B], regD[C]);
|
2018-09-11 20:48:02 +00:00
|
|
|
if (check) cc.je(fail);
|
|
|
|
else cc.jne(fail);
|
2018-08-18 23:46:56 +00:00
|
|
|
});
|
|
|
|
}
|
2018-08-12 00:11:13 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitEQ_K()
|
|
|
|
{
|
2018-09-11 20:48:02 +00:00
|
|
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.cmp(regD[B], konstd[C]);
|
2018-09-11 20:48:02 +00:00
|
|
|
if (check) cc.je(fail);
|
|
|
|
else cc.jne(fail);
|
2018-08-18 23:46:56 +00:00
|
|
|
});
|
|
|
|
}
|
2018-08-12 00:11:13 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLT_RR()
|
|
|
|
{
|
2018-09-11 20:48:02 +00:00
|
|
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.cmp(regD[B], regD[C]);
|
2018-09-11 20:48:02 +00:00
|
|
|
if (check) cc.jl(fail);
|
|
|
|
else cc.jnl(fail);
|
2018-08-18 23:46:56 +00:00
|
|
|
});
|
|
|
|
}
|
2018-08-12 00:11:13 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLT_RK()
|
|
|
|
{
|
2018-09-11 20:48:02 +00:00
|
|
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.cmp(regD[B], konstd[C]);
|
2018-09-11 20:48:02 +00:00
|
|
|
if (check) cc.jl(fail);
|
|
|
|
else cc.jnl(fail);
|
2018-08-18 23:46:56 +00:00
|
|
|
});
|
|
|
|
}
|
2018-08-12 00:11:13 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLT_KR()
|
|
|
|
{
|
2018-09-11 20:48:02 +00:00
|
|
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
2018-08-18 23:46:56 +00:00
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, ToMemAddress(&konstd[B]));
|
|
|
|
cc.cmp(asmjit::x86::ptr(tmp), regD[C]);
|
2018-09-11 20:48:02 +00:00
|
|
|
if (check) cc.jl(fail);
|
|
|
|
else cc.jnl(fail);
|
2018-08-18 23:46:56 +00:00
|
|
|
});
|
|
|
|
}
|
2018-08-12 00:11:13 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLE_RR()
|
|
|
|
{
|
2018-09-11 20:48:02 +00:00
|
|
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.cmp(regD[B], regD[C]);
|
2018-09-11 20:48:02 +00:00
|
|
|
if (check) cc.jle(fail);
|
|
|
|
else cc.jnle(fail);
|
2018-08-18 23:46:56 +00:00
|
|
|
});
|
|
|
|
}
|
2018-08-12 00:11:13 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLE_RK()
|
|
|
|
{
|
2018-09-11 20:48:02 +00:00
|
|
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.cmp(regD[B], konstd[C]);
|
2018-09-11 20:48:02 +00:00
|
|
|
if (check) cc.jle(fail);
|
|
|
|
else cc.jnle(fail);
|
2018-08-18 23:46:56 +00:00
|
|
|
});
|
|
|
|
}
|
2018-08-12 00:11:13 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLE_KR()
|
|
|
|
{
|
2018-09-11 20:48:02 +00:00
|
|
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
2018-08-18 23:46:56 +00:00
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, ToMemAddress(&konstd[B]));
|
|
|
|
cc.cmp(asmjit::x86::ptr(tmp), regD[C]);
|
2018-09-11 20:48:02 +00:00
|
|
|
if (check) cc.jle(fail);
|
|
|
|
else cc.jnle(fail);
|
2018-08-18 23:46:56 +00:00
|
|
|
});
|
|
|
|
}
|
2018-08-12 00:11:13 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLTU_RR()
|
|
|
|
{
|
2018-09-11 20:48:02 +00:00
|
|
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.cmp(regD[B], regD[C]);
|
2018-09-11 20:48:02 +00:00
|
|
|
if (check) cc.jb(fail);
|
|
|
|
else cc.jnb(fail);
|
2018-08-18 23:46:56 +00:00
|
|
|
});
|
|
|
|
}
|
2018-08-12 00:11:13 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLTU_RK()
|
|
|
|
{
|
2018-09-11 20:48:02 +00:00
|
|
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.cmp(regD[B], konstd[C]);
|
2018-09-11 20:48:02 +00:00
|
|
|
if (check) cc.jb(fail);
|
|
|
|
else cc.jnb(fail);
|
2018-08-18 23:46:56 +00:00
|
|
|
});
|
|
|
|
}
|
2018-08-12 00:11:13 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLTU_KR()
|
|
|
|
{
|
2018-09-11 20:48:02 +00:00
|
|
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
2018-08-18 23:46:56 +00:00
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, ToMemAddress(&konstd[B]));
|
|
|
|
cc.cmp(asmjit::x86::ptr(tmp), regD[C]);
|
2018-09-11 20:48:02 +00:00
|
|
|
if (check) cc.jb(fail);
|
|
|
|
else cc.jnb(fail);
|
2018-08-18 23:46:56 +00:00
|
|
|
});
|
|
|
|
}
|
2018-08-12 00:11:13 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLEU_RR()
|
|
|
|
{
|
2018-09-11 20:48:02 +00:00
|
|
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.cmp(regD[B], regD[C]);
|
2018-09-11 20:48:02 +00:00
|
|
|
if (check) cc.jbe(fail);
|
|
|
|
else cc.jnbe(fail);
|
2018-08-18 23:46:56 +00:00
|
|
|
});
|
|
|
|
}
|
2018-08-12 00:11:13 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLEU_RK()
|
|
|
|
{
|
2018-09-11 20:48:02 +00:00
|
|
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.cmp(regD[B], konstd[C]);
|
2018-09-11 20:48:02 +00:00
|
|
|
if (check) cc.jbe(fail);
|
|
|
|
else cc.jnbe(fail);
|
2018-08-18 23:46:56 +00:00
|
|
|
});
|
|
|
|
}
|
2018-08-12 00:11:13 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitLEU_KR()
|
|
|
|
{
|
2018-09-11 20:48:02 +00:00
|
|
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
2018-08-18 23:46:56 +00:00
|
|
|
auto tmp = cc.newIntPtr();
|
2018-09-11 20:48:02 +00:00
|
|
|
cc.mov(tmp, ToMemAddress(&konstd[B]));
|
|
|
|
cc.cmp(asmjit::x86::ptr(tmp), regD[C]);
|
|
|
|
if (check) cc.jbe(fail);
|
|
|
|
else cc.jnbe(fail);
|
2018-08-18 23:46:56 +00:00
|
|
|
});
|
|
|
|
}
|
2018-08-14 23:07:50 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
// Double-precision floating point math.
|
2018-08-14 23:07:50 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitADDF_RR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc = CheckRegF(C, A);
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.movsd(regF[A], regF[B]);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.addsd(regF[A], rc);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-14 23:07:50 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitADDF_RK()
|
|
|
|
{
|
|
|
|
auto tmp = cc.newIntPtr();
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.movsd(regF[A], regF[B]);
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.mov(tmp, ToMemAddress(&konstf[C]));
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.addsd(regF[A], asmjit::x86::qword_ptr(tmp));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-14 23:07:50 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitSUBF_RR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc = CheckRegF(C, A);
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.movsd(regF[A], regF[B]);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.subsd(regF[A], rc);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-18 17:03:18 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitSUBF_RK()
|
|
|
|
{
|
|
|
|
auto tmp = cc.newIntPtr();
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.movsd(regF[A], regF[B]);
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.mov(tmp, ToMemAddress(&konstf[C]));
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.subsd(regF[A], asmjit::x86::qword_ptr(tmp));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-18 17:03:18 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitSUBF_KR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc = CheckRegF(C, A);
|
2018-08-18 23:46:56 +00:00
|
|
|
auto tmp = cc.newIntPtr();
|
2018-08-30 16:47:25 +00:00
|
|
|
cc.mov(tmp, ToMemAddress(&konstf[B]));
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsd(regF[A], asmjit::x86::qword_ptr(tmp));
|
|
|
|
cc.subsd(regF[A], rc);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-18 17:03:18 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitMULF_RR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc = CheckRegF(C, A);
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.movsd(regF[A], regF[B]);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mulsd(regF[A], rc);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitMULF_RK()
|
|
|
|
{
|
|
|
|
auto tmp = cc.newIntPtr();
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.movsd(regF[A], regF[B]);
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.mov(tmp, ToMemAddress(&konstf[C]));
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mulsd(regF[A], asmjit::x86::qword_ptr(tmp));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitDIVF_RR()
|
|
|
|
{
|
2018-08-24 21:17:35 +00:00
|
|
|
auto label = cc.newLabel();
|
2018-08-25 11:38:45 +00:00
|
|
|
cc.ptest(regF[C], regF[C]);
|
2018-08-24 21:17:35 +00:00
|
|
|
cc.jne(label);
|
|
|
|
EmitThrowException(X_DIVISION_BY_ZERO);
|
|
|
|
cc.bind(label);
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc = CheckRegF(C, A);
|
|
|
|
cc.movsd(regF[A], regF[B]);
|
|
|
|
cc.divsd(regF[A], rc);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitDIVF_RK()
|
|
|
|
{
|
2018-08-24 21:17:35 +00:00
|
|
|
if (konstf[C] == 0.)
|
|
|
|
{
|
|
|
|
EmitThrowException(X_DIVISION_BY_ZERO);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
auto tmp = cc.newIntPtr();
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsd(regF[A], regF[B]);
|
2018-08-24 21:17:35 +00:00
|
|
|
cc.mov(tmp, ToMemAddress(&konstf[C]));
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.divsd(regF[A], asmjit::x86::qword_ptr(tmp));
|
2018-08-24 21:17:35 +00:00
|
|
|
}
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitDIVF_KR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc = CheckRegF(C, A);
|
2018-08-18 23:46:56 +00:00
|
|
|
auto tmp = cc.newIntPtr();
|
2018-08-24 21:17:35 +00:00
|
|
|
cc.mov(tmp, ToMemAddress(&konstf[B]));
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsd(regF[A], asmjit::x86::qword_ptr(tmp));
|
|
|
|
cc.divsd(regF[A], rc);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
2018-08-28 23:27:37 +00:00
|
|
|
void EmitMODF_RR()
|
|
|
|
{
|
|
|
|
using namespace asmjit;
|
|
|
|
typedef double(*FuncPtr)(double, double);
|
|
|
|
|
|
|
|
auto label = cc.newLabel();
|
|
|
|
cc.ptest(regF[C], regF[C]);
|
|
|
|
cc.jne(label);
|
|
|
|
EmitThrowException(X_DIVISION_BY_ZERO);
|
|
|
|
cc.bind(label);
|
|
|
|
|
|
|
|
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(static_cast<FuncPtr>([](double a, double b) -> double
|
|
|
|
{
|
|
|
|
return a - floor(a / b) * b;
|
|
|
|
}))), FuncSignature2<double, double, double>());
|
2018-09-02 13:36:39 +00:00
|
|
|
call->setRet(0, regF[A]);
|
2018-08-28 23:27:37 +00:00
|
|
|
call->setArg(0, regF[B]);
|
|
|
|
call->setArg(1, regF[C]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitMODF_RK()
|
|
|
|
{
|
|
|
|
using namespace asmjit;
|
|
|
|
typedef double(*FuncPtr)(double, double);
|
|
|
|
|
|
|
|
auto label = cc.newLabel();
|
|
|
|
cc.ptest(regF[C], regF[C]);
|
|
|
|
cc.jne(label);
|
|
|
|
EmitThrowException(X_DIVISION_BY_ZERO);
|
|
|
|
cc.bind(label);
|
|
|
|
|
|
|
|
auto tmp = cc.newXmm();
|
|
|
|
cc.movsd(tmp, x86::ptr(ToMemAddress(&konstf[C])));
|
|
|
|
|
|
|
|
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(static_cast<FuncPtr>([](double a, double b) -> double {
|
|
|
|
return a - floor(a / b) * b;
|
|
|
|
}))), FuncSignature2<double, double, double>());
|
2018-09-02 13:36:39 +00:00
|
|
|
call->setRet(0, regF[A]);
|
2018-08-28 23:27:37 +00:00
|
|
|
call->setArg(0, regF[B]);
|
|
|
|
call->setArg(1, tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitMODF_KR()
|
|
|
|
{
|
|
|
|
using namespace asmjit;
|
|
|
|
typedef double(*FuncPtr)(double, double);
|
|
|
|
|
|
|
|
auto label = cc.newLabel();
|
|
|
|
cc.ptest(regF[C], regF[C]);
|
|
|
|
cc.jne(label);
|
|
|
|
EmitThrowException(X_DIVISION_BY_ZERO);
|
|
|
|
cc.bind(label);
|
|
|
|
|
|
|
|
auto tmp = cc.newXmm();
|
|
|
|
cc.movsd(tmp, x86::ptr(ToMemAddress(&konstf[B])));
|
|
|
|
|
|
|
|
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(static_cast<FuncPtr>([](double a, double b) -> double {
|
|
|
|
return a - floor(a / b) * b;
|
|
|
|
}))), FuncSignature2<double, double, double>());
|
2018-09-02 13:36:39 +00:00
|
|
|
call->setRet(0, regF[A]);
|
2018-08-28 23:27:37 +00:00
|
|
|
call->setArg(0, tmp);
|
|
|
|
call->setArg(1, regF[C]);
|
|
|
|
}
|
2018-08-24 21:17:35 +00:00
|
|
|
|
|
|
|
void EmitPOWF_RR()
|
|
|
|
{
|
|
|
|
using namespace asmjit;
|
|
|
|
typedef double(*FuncPtr)(double, double);
|
|
|
|
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(static_cast<FuncPtr>(g_pow))), FuncSignature2<double, double, double>());
|
2018-09-02 13:36:39 +00:00
|
|
|
call->setRet(0, regF[A]);
|
2018-08-24 21:17:35 +00:00
|
|
|
call->setArg(0, regF[B]);
|
|
|
|
call->setArg(1, regF[C]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitPOWF_RK()
|
|
|
|
{
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
auto tmp2 = cc.newXmm();
|
|
|
|
cc.mov(tmp, ToMemAddress(&konstf[C]));
|
|
|
|
cc.movsd(tmp2, asmjit::x86::qword_ptr(tmp));
|
|
|
|
|
|
|
|
using namespace asmjit;
|
|
|
|
typedef double(*FuncPtr)(double, double);
|
|
|
|
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(static_cast<FuncPtr>(g_pow))), FuncSignature2<double, double, double>());
|
2018-09-02 13:36:39 +00:00
|
|
|
call->setRet(0, regF[A]);
|
2018-08-24 21:17:35 +00:00
|
|
|
call->setArg(0, regF[B]);
|
|
|
|
call->setArg(1, tmp2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitPOWF_KR()
|
|
|
|
{
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
auto tmp2 = cc.newXmm();
|
|
|
|
cc.mov(tmp, ToMemAddress(&konstf[B]));
|
|
|
|
cc.movsd(tmp2, asmjit::x86::qword_ptr(tmp));
|
|
|
|
|
|
|
|
using namespace asmjit;
|
|
|
|
typedef double(*FuncPtr)(double, double);
|
|
|
|
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(static_cast<FuncPtr>(g_pow))), FuncSignature2<double, double, double>());
|
2018-09-02 13:36:39 +00:00
|
|
|
call->setRet(0, regF[A]);
|
2018-08-24 21:17:35 +00:00
|
|
|
call->setArg(0, tmp2);
|
|
|
|
call->setArg(1, regF[C]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitMINF_RR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc = CheckRegF(C, A);
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.movsd(regF[A], regF[B]);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.minsd(regF[A], rc);
|
2018-08-24 21:17:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitMINF_RK()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rb = CheckRegF(B, A);
|
2018-08-24 21:17:35 +00:00
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, ToMemAddress(&konstf[C]));
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsd(regF[A], asmjit::x86::qword_ptr(tmp));
|
|
|
|
cc.minsd(regF[A], rb);
|
2018-08-24 21:17:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitMAXF_RR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc = CheckRegF(C, A);
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.movsd(regF[A], regF[B]);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.maxsd(regF[A], rc);
|
2018-08-24 21:17:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitMAXF_RK()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rb = CheckRegF(B, A);
|
2018-08-24 21:17:35 +00:00
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, ToMemAddress(&konstf[C]));
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsd(regF[A], asmjit::x86::qword_ptr(tmp));
|
|
|
|
cc.maxsd(regF[A], rb);
|
2018-08-24 21:17:35 +00:00
|
|
|
}
|
2018-08-19 23:40:37 +00:00
|
|
|
|
|
|
|
void EmitATAN2()
|
|
|
|
{
|
|
|
|
using namespace asmjit;
|
|
|
|
typedef double(*FuncPtr)(double, double);
|
|
|
|
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(static_cast<FuncPtr>(g_atan2))), FuncSignature2<double, double, double>());
|
2018-09-02 13:36:39 +00:00
|
|
|
call->setRet(0, regF[A]);
|
2018-08-19 23:40:37 +00:00
|
|
|
call->setArg(0, regF[B]);
|
|
|
|
call->setArg(1, regF[C]);
|
|
|
|
|
|
|
|
static const double constant = 180 / M_PI;
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, ToMemAddress(&constant));
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mulsd(regF[A], asmjit::x86::qword_ptr(tmp));
|
2018-08-19 23:40:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitFLOP()
|
|
|
|
{
|
|
|
|
if (C == FLOP_NEG)
|
|
|
|
{
|
2018-08-24 21:17:35 +00:00
|
|
|
auto mask = cc.newDoubleConst(asmjit::kConstScopeLocal, -0.0);
|
|
|
|
auto maskXmm = cc.newXmmSd();
|
|
|
|
cc.movsd(maskXmm, mask);
|
2018-09-11 21:31:32 +00:00
|
|
|
if (A != B)
|
|
|
|
cc.movsd(regF[A], regF[B]);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.xorpd(regF[A], maskXmm);
|
2018-08-19 23:40:37 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
auto v = cc.newXmm();
|
|
|
|
cc.movsd(v, regF[B]);
|
|
|
|
|
|
|
|
if (C == FLOP_TAN_DEG)
|
|
|
|
{
|
|
|
|
static const double constant = M_PI / 180;
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, ToMemAddress(&constant));
|
|
|
|
cc.mulsd(v, asmjit::x86::qword_ptr(tmp));
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef double(*FuncPtr)(double);
|
|
|
|
FuncPtr func = nullptr;
|
|
|
|
switch (C)
|
|
|
|
{
|
|
|
|
default: I_FatalError("Unknown OP_FLOP subfunction");
|
|
|
|
case FLOP_ABS: func = fabs; break;
|
|
|
|
case FLOP_EXP: func = g_exp; break;
|
|
|
|
case FLOP_LOG: func = g_log; break;
|
|
|
|
case FLOP_LOG10: func = g_log10; break;
|
|
|
|
case FLOP_SQRT: func = g_sqrt; break;
|
|
|
|
case FLOP_CEIL: func = ceil; break;
|
|
|
|
case FLOP_FLOOR: func = floor; break;
|
|
|
|
case FLOP_ACOS: func = g_acos; break;
|
|
|
|
case FLOP_ASIN: func = g_asin; break;
|
|
|
|
case FLOP_ATAN: func = g_atan; break;
|
|
|
|
case FLOP_COS: func = g_cos; break;
|
|
|
|
case FLOP_SIN: func = g_sin; break;
|
|
|
|
case FLOP_TAN: func = g_tan; break;
|
|
|
|
case FLOP_ACOS_DEG: func = g_acos; break;
|
|
|
|
case FLOP_ASIN_DEG: func = g_asin; break;
|
|
|
|
case FLOP_ATAN_DEG: func = g_atan; break;
|
|
|
|
case FLOP_COS_DEG: func = g_cosdeg; break;
|
|
|
|
case FLOP_SIN_DEG: func = g_sindeg; break;
|
|
|
|
case FLOP_TAN_DEG: func = g_tan; break;
|
|
|
|
case FLOP_COSH: func = g_cosh; break;
|
|
|
|
case FLOP_SINH: func = g_sinh; break;
|
|
|
|
case FLOP_TANH: func = g_tanh; break;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(func)), asmjit::FuncSignature1<double, double>());
|
2018-09-02 13:36:39 +00:00
|
|
|
call->setRet(0, regF[A]);
|
2018-08-19 23:40:37 +00:00
|
|
|
call->setArg(0, v);
|
|
|
|
|
|
|
|
if (C == FLOP_ACOS_DEG || C == FLOP_ASIN_DEG || C == FLOP_ATAN_DEG)
|
|
|
|
{
|
|
|
|
static const double constant = 180 / M_PI;
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, ToMemAddress(&constant));
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mulsd(regF[A], asmjit::x86::qword_ptr(tmp));
|
2018-08-19 23:40:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-08-18 23:46:56 +00:00
|
|
|
|
|
|
|
void EmitEQF_R()
|
|
|
|
{
|
2018-09-11 20:48:02 +00:00
|
|
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
2018-08-18 23:46:56 +00:00
|
|
|
bool approx = static_cast<bool>(A & CMP_APPROX);
|
|
|
|
if (!approx)
|
2018-08-17 21:06:12 +00:00
|
|
|
{
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.ucomisd(regF[B], regF[C]);
|
2018-09-11 20:48:02 +00:00
|
|
|
if (check) {
|
|
|
|
cc.jp(success);
|
|
|
|
cc.je(fail);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
cc.jp(fail);
|
|
|
|
cc.jne(fail);
|
|
|
|
}
|
2018-08-17 21:06:12 +00:00
|
|
|
}
|
2018-08-18 23:46:56 +00:00
|
|
|
else
|
2018-08-17 21:06:12 +00:00
|
|
|
{
|
2018-08-18 23:46:56 +00:00
|
|
|
auto tmp = cc.newXmmSd();
|
|
|
|
|
|
|
|
const int64_t absMaskInt = 0x7FFFFFFFFFFFFFFF;
|
|
|
|
auto absMask = cc.newDoubleConst(asmjit::kConstScopeLocal, reinterpret_cast<const double&>(absMaskInt));
|
|
|
|
auto absMaskXmm = cc.newXmmPd();
|
|
|
|
|
|
|
|
auto epsilon = cc.newDoubleConst(asmjit::kConstScopeLocal, VM_EPSILON);
|
|
|
|
auto epsilonXmm = cc.newXmmSd();
|
|
|
|
|
|
|
|
cc.movsd(tmp, regF[B]);
|
|
|
|
cc.subsd(tmp, regF[C]);
|
|
|
|
cc.movsd(absMaskXmm, absMask);
|
|
|
|
cc.andpd(tmp, absMaskXmm);
|
|
|
|
cc.movsd(epsilonXmm, epsilon);
|
|
|
|
cc.ucomisd(epsilonXmm, tmp);
|
2018-09-11 20:48:02 +00:00
|
|
|
|
|
|
|
if (check) cc.ja(fail);
|
|
|
|
else cc.jna(fail);
|
2018-08-17 21:06:12 +00:00
|
|
|
}
|
2018-08-18 23:46:56 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitEQF_K()
|
|
|
|
{
|
|
|
|
using namespace asmjit;
|
2018-09-11 20:48:02 +00:00
|
|
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
2018-08-18 23:46:56 +00:00
|
|
|
bool approx = static_cast<bool>(A & CMP_APPROX);
|
|
|
|
if (!approx) {
|
2018-08-17 21:06:12 +00:00
|
|
|
auto konstTmp = cc.newIntPtr();
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.mov(konstTmp, ToMemAddress(&konstf[C]));
|
|
|
|
cc.ucomisd(regF[B], x86::qword_ptr(konstTmp));
|
2018-09-11 20:48:02 +00:00
|
|
|
if (check) {
|
|
|
|
cc.jp(success);
|
|
|
|
cc.je(fail);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
cc.jp(fail);
|
|
|
|
cc.jne(fail);
|
|
|
|
}
|
2018-08-17 21:06:12 +00:00
|
|
|
}
|
2018-08-18 23:46:56 +00:00
|
|
|
else {
|
2018-08-17 21:06:12 +00:00
|
|
|
auto konstTmp = cc.newIntPtr();
|
2018-08-18 23:46:56 +00:00
|
|
|
auto subTmp = cc.newXmmSd();
|
2018-08-14 12:02:56 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
const int64_t absMaskInt = 0x7FFFFFFFFFFFFFFF;
|
|
|
|
auto absMask = cc.newDoubleConst(kConstScopeLocal, reinterpret_cast<const double&>(absMaskInt));
|
|
|
|
auto absMaskXmm = cc.newXmmPd();
|
|
|
|
|
|
|
|
auto epsilon = cc.newDoubleConst(kConstScopeLocal, VM_EPSILON);
|
|
|
|
auto epsilonXmm = cc.newXmmSd();
|
|
|
|
|
|
|
|
cc.mov(konstTmp, ToMemAddress(&konstf[C]));
|
|
|
|
|
|
|
|
cc.movsd(subTmp, regF[B]);
|
|
|
|
cc.subsd(subTmp, x86::qword_ptr(konstTmp));
|
|
|
|
cc.movsd(absMaskXmm, absMask);
|
|
|
|
cc.andpd(subTmp, absMaskXmm);
|
|
|
|
cc.movsd(epsilonXmm, epsilon);
|
|
|
|
cc.ucomisd(epsilonXmm, subTmp);
|
2018-09-11 20:48:02 +00:00
|
|
|
|
|
|
|
if (check) cc.ja(fail);
|
|
|
|
else cc.jna(fail);
|
2018-08-14 12:02:56 +00:00
|
|
|
}
|
2018-08-18 23:46:56 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitLTF_RR()
|
|
|
|
{
|
2018-09-11 20:48:02 +00:00
|
|
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
2018-09-02 22:44:25 +00:00
|
|
|
if (static_cast<bool>(A & CMP_APPROX)) I_FatalError("CMP_APPROX not implemented for LTF_RR.\n");
|
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.ucomisd(regF[C], regF[B]);
|
2018-09-11 20:48:02 +00:00
|
|
|
if (check) cc.ja(fail);
|
|
|
|
else cc.jna(fail);
|
2018-08-18 23:46:56 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitLTF_RK()
|
|
|
|
{
|
2018-09-11 20:48:02 +00:00
|
|
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
2018-09-02 22:44:25 +00:00
|
|
|
if (static_cast<bool>(A & CMP_APPROX)) I_FatalError("CMP_APPROX not implemented for LTF_RK.\n");
|
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
auto constTmp = cc.newIntPtr();
|
|
|
|
auto xmmTmp = cc.newXmmSd();
|
|
|
|
cc.mov(constTmp, ToMemAddress(&konstf[C]));
|
|
|
|
cc.movsd(xmmTmp, asmjit::x86::qword_ptr(constTmp));
|
|
|
|
|
|
|
|
cc.ucomisd(xmmTmp, regF[B]);
|
2018-09-11 20:48:02 +00:00
|
|
|
if (check) cc.ja(fail);
|
|
|
|
else cc.jna(fail);
|
2018-08-18 23:46:56 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitLTF_KR()
|
|
|
|
{
|
2018-09-11 20:48:02 +00:00
|
|
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
2018-09-02 22:44:25 +00:00
|
|
|
if (static_cast<bool>(A & CMP_APPROX)) I_FatalError("CMP_APPROX not implemented for LTF_KR.\n");
|
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, ToMemAddress(&konstf[B]));
|
|
|
|
|
|
|
|
cc.ucomisd(regF[C], asmjit::x86::qword_ptr(tmp));
|
2018-09-11 20:48:02 +00:00
|
|
|
if (check) cc.ja(fail);
|
|
|
|
else cc.jna(fail);
|
2018-08-18 23:46:56 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitLEF_RR()
|
|
|
|
{
|
2018-09-11 20:48:02 +00:00
|
|
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
2018-09-02 22:44:25 +00:00
|
|
|
if (static_cast<bool>(A & CMP_APPROX)) I_FatalError("CMP_APPROX not implemented for LEF_RR.\n");
|
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.ucomisd(regF[C], regF[B]);
|
2018-09-11 20:48:02 +00:00
|
|
|
if (check) cc.jae(fail);
|
|
|
|
else cc.jnae(fail);
|
2018-08-18 23:46:56 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitLEF_RK()
|
|
|
|
{
|
2018-09-11 20:48:02 +00:00
|
|
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
2018-09-02 22:44:25 +00:00
|
|
|
if (static_cast<bool>(A & CMP_APPROX)) I_FatalError("CMP_APPROX not implemented for LEF_RK.\n");
|
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
auto constTmp = cc.newIntPtr();
|
|
|
|
auto xmmTmp = cc.newXmmSd();
|
|
|
|
cc.mov(constTmp, ToMemAddress(&konstf[C]));
|
|
|
|
cc.movsd(xmmTmp, asmjit::x86::qword_ptr(constTmp));
|
|
|
|
|
|
|
|
cc.ucomisd(xmmTmp, regF[B]);
|
2018-09-11 20:48:02 +00:00
|
|
|
if (check) cc.jae(fail);
|
|
|
|
else cc.jnae(fail);
|
2018-08-18 23:46:56 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitLEF_KR()
|
|
|
|
{
|
2018-09-11 20:48:02 +00:00
|
|
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
2018-09-02 22:45:32 +00:00
|
|
|
if (static_cast<bool>(A & CMP_APPROX)) I_FatalError("CMP_APPROX not implemented for LEF_KR.\n");
|
2018-09-02 22:44:25 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, ToMemAddress(&konstf[B]));
|
|
|
|
|
|
|
|
cc.ucomisd(regF[C], asmjit::x86::qword_ptr(tmp));
|
2018-09-11 20:48:02 +00:00
|
|
|
if (check) cc.jae(fail);
|
|
|
|
else cc.jnae(fail);
|
2018-08-18 23:46:56 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// Vector math. (2D)
|
|
|
|
|
|
|
|
void EmitNEGV2()
|
|
|
|
{
|
2018-08-24 21:17:35 +00:00
|
|
|
auto mask = cc.newDoubleConst(asmjit::kConstScopeLocal, -0.0);
|
|
|
|
auto maskXmm = cc.newXmmSd();
|
|
|
|
cc.movsd(maskXmm, mask);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsd(regF[A], regF[B]);
|
|
|
|
cc.xorpd(regF[A], maskXmm);
|
|
|
|
cc.movsd(regF[A + 1], regF[B + 1]);
|
|
|
|
cc.xorpd(regF[A + 1], maskXmm);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitADDV2_RR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc0 = CheckRegF(C, A);
|
|
|
|
auto rc1 = CheckRegF(C + 1, A + 1);
|
|
|
|
cc.movsd(regF[A], regF[B]);
|
|
|
|
cc.movsd(regF[A + 1], regF[B + 1]);
|
|
|
|
cc.addsd(regF[A], rc0);
|
|
|
|
cc.addsd(regF[A + 1], rc1);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSUBV2_RR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc0 = CheckRegF(C, A);
|
|
|
|
auto rc1 = CheckRegF(C + 1, A + 1);
|
|
|
|
cc.movsd(regF[A], regF[B]);
|
|
|
|
cc.movsd(regF[A + 1], regF[B + 1]);
|
|
|
|
cc.subsd(regF[A], rc0);
|
|
|
|
cc.subsd(regF[A + 1], rc1);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitDOTV2_RR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc0 = CheckRegF(C, A);
|
|
|
|
auto rc1 = CheckRegF(C + 1, A);
|
2018-08-18 23:46:56 +00:00
|
|
|
auto tmp = cc.newXmmSd();
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsd(regF[A], regF[B]);
|
|
|
|
cc.mulsd(regF[A], rc0);
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.movsd(tmp, regF[B + 1]);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mulsd(tmp, rc1);
|
|
|
|
cc.addsd(regF[A], tmp);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitMULVF2_RR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc = CheckRegF(C, A, A + 1);
|
|
|
|
cc.movsd(regF[A], regF[B]);
|
|
|
|
cc.movsd(regF[A + 1], regF[B + 1]);
|
|
|
|
cc.mulsd(regF[A], rc);
|
|
|
|
cc.mulsd(regF[A + 1], rc);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitMULVF2_RK()
|
|
|
|
{
|
|
|
|
auto tmp = cc.newIntPtr();
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsd(regF[A], regF[B]);
|
|
|
|
cc.movsd(regF[A + 1], regF[B + 1]);
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.mov(tmp, ToMemAddress(&konstf[C]));
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mulsd(regF[A], asmjit::x86::qword_ptr(tmp));
|
|
|
|
cc.mulsd(regF[A + 1], asmjit::x86::qword_ptr(tmp));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitDIVVF2_RR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc = CheckRegF(C, A, A + 1);
|
|
|
|
cc.movsd(regF[A], regF[B]);
|
|
|
|
cc.movsd(regF[A + 1], regF[B + 1]);
|
|
|
|
cc.divsd(regF[A], rc);
|
|
|
|
cc.divsd(regF[A + 1], rc);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitDIVVF2_RK()
|
|
|
|
{
|
|
|
|
auto tmp = cc.newIntPtr();
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsd(regF[A], regF[B]);
|
|
|
|
cc.movsd(regF[A + 1], regF[B + 1]);
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.mov(tmp, ToMemAddress(&konstf[C]));
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.divsd(regF[A], asmjit::x86::qword_ptr(tmp));
|
|
|
|
cc.divsd(regF[A + 1], asmjit::x86::qword_ptr(tmp));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitLENV2()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rb0 = CheckRegF(B, A);
|
|
|
|
auto rb1 = CheckRegF(B + 1, A);
|
2018-08-18 23:46:56 +00:00
|
|
|
auto tmp = cc.newXmmSd();
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsd(regF[A], regF[B]);
|
|
|
|
cc.mulsd(regF[A], rb0);
|
|
|
|
cc.movsd(tmp, rb1);
|
|
|
|
cc.mulsd(tmp, rb1);
|
|
|
|
cc.addsd(regF[A], tmp);
|
|
|
|
CallSqrt(regF[A], regF[A]);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
2018-09-02 22:44:25 +00:00
|
|
|
void EmitEQV2_R()
|
|
|
|
{
|
2018-09-11 20:48:02 +00:00
|
|
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
2018-09-02 22:44:25 +00:00
|
|
|
if (static_cast<bool>(A & CMP_APPROX)) I_FatalError("CMP_APPROX not implemented for EQV2_R.\n");
|
|
|
|
|
|
|
|
cc.ucomisd(regF[B], regF[C]);
|
2018-09-11 20:48:02 +00:00
|
|
|
if (check) {
|
|
|
|
cc.jp(success);
|
|
|
|
cc.jne(success);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
cc.jp(fail);
|
|
|
|
cc.jne(fail);
|
|
|
|
}
|
2018-09-02 22:44:25 +00:00
|
|
|
|
|
|
|
cc.ucomisd(regF[B + 1], regF[C + 1]);
|
2018-09-11 20:48:02 +00:00
|
|
|
if (check) {
|
|
|
|
cc.jp(success);
|
|
|
|
cc.je(fail);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
cc.jp(fail);
|
|
|
|
cc.jne(fail);
|
|
|
|
}
|
2018-09-02 22:44:25 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitEQV2_K()
|
|
|
|
{
|
|
|
|
I_FatalError("EQV2_K is not used.");
|
|
|
|
}
|
2018-08-18 23:46:56 +00:00
|
|
|
|
|
|
|
// Vector math. (3D)
|
|
|
|
|
|
|
|
void EmitNEGV3()
|
|
|
|
{
|
2018-08-24 21:17:35 +00:00
|
|
|
auto mask = cc.newDoubleConst(asmjit::kConstScopeLocal, -0.0);
|
|
|
|
auto maskXmm = cc.newXmmSd();
|
|
|
|
cc.movsd(maskXmm, mask);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsd(regF[A], regF[B]);
|
|
|
|
cc.xorpd(regF[A], maskXmm);
|
|
|
|
cc.movsd(regF[A + 1], regF[B + 1]);
|
|
|
|
cc.xorpd(regF[A + 1], maskXmm);
|
|
|
|
cc.movsd(regF[A + 2], regF[B + 2]);
|
|
|
|
cc.xorpd(regF[A + 2], maskXmm);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitADDV3_RR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc0 = CheckRegF(C, A);
|
|
|
|
auto rc1 = CheckRegF(C + 1, A + 1);
|
|
|
|
auto rc2 = CheckRegF(C + 2, A + 2);
|
|
|
|
cc.movsd(regF[A], regF[B]);
|
|
|
|
cc.movsd(regF[A + 1], regF[B + 1]);
|
|
|
|
cc.movsd(regF[A + 2], regF[B + 2]);
|
|
|
|
cc.addsd(regF[A], rc0);
|
|
|
|
cc.addsd(regF[A + 1], rc1);
|
|
|
|
cc.addsd(regF[A + 2], rc2);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitSUBV3_RR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc0 = CheckRegF(C, A);
|
|
|
|
auto rc1 = CheckRegF(C + 1, A + 1);
|
|
|
|
auto rc2 = CheckRegF(C + 2, A + 2);
|
|
|
|
cc.movsd(regF[A], regF[B]);
|
|
|
|
cc.movsd(regF[A + 1], regF[B + 1]);
|
|
|
|
cc.movsd(regF[A + 2], regF[B + 2]);
|
|
|
|
cc.subsd(regF[A], rc0);
|
|
|
|
cc.subsd(regF[A + 1], rc1);
|
|
|
|
cc.subsd(regF[A + 2], rc2);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitDOTV3_RR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rb1 = CheckRegF(B + 1, A);
|
|
|
|
auto rb2 = CheckRegF(B + 2, A);
|
|
|
|
auto rc0 = CheckRegF(C, A);
|
|
|
|
auto rc1 = CheckRegF(C + 1, A);
|
|
|
|
auto rc2 = CheckRegF(C + 2, A);
|
2018-08-18 23:46:56 +00:00
|
|
|
auto tmp = cc.newXmmSd();
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsd(regF[A], regF[B]);
|
|
|
|
cc.mulsd(regF[A], rc0);
|
|
|
|
cc.movsd(tmp, rb1);
|
|
|
|
cc.mulsd(tmp, rc1);
|
|
|
|
cc.addsd(regF[A], tmp);
|
|
|
|
cc.movsd(tmp, rb2);
|
|
|
|
cc.mulsd(tmp, rc2);
|
|
|
|
cc.addsd(regF[A], tmp);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitCROSSV_RR()
|
|
|
|
{
|
|
|
|
auto tmp = cc.newXmmSd();
|
2018-09-02 13:36:39 +00:00
|
|
|
|
|
|
|
auto a0 = CheckRegF(B, A);
|
|
|
|
auto a1 = CheckRegF(B + 1, A + 1);
|
|
|
|
auto a2 = CheckRegF(B + 2, A + 2);
|
|
|
|
auto b0 = CheckRegF(C, A);
|
|
|
|
auto b1 = CheckRegF(C + 1, A + 1);
|
|
|
|
auto b2 = CheckRegF(C + 2, A + 2);
|
2018-08-18 23:46:56 +00:00
|
|
|
|
|
|
|
// r0 = a1b2 - a2b1
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsd(regF[A], a1);
|
|
|
|
cc.mulsd(regF[A], b2);
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.movsd(tmp, a2);
|
|
|
|
cc.mulsd(tmp, b1);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.subsd(regF[A], tmp);
|
2018-08-18 23:46:56 +00:00
|
|
|
|
|
|
|
// r1 = a2b0 - a0b2
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsd(regF[A + 1], a2);
|
|
|
|
cc.mulsd(regF[A + 1], b0);
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.movsd(tmp, a0);
|
|
|
|
cc.mulsd(tmp, b2);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.subsd(regF[A + 1], tmp);
|
2018-08-18 23:46:56 +00:00
|
|
|
|
|
|
|
// r2 = a0b1 - a1b0
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsd(regF[A + 2], a0);
|
|
|
|
cc.mulsd(regF[A + 2], b1);
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.movsd(tmp, a1);
|
|
|
|
cc.mulsd(tmp, b0);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.subsd(regF[A + 2], tmp);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitMULVF3_RR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc = CheckRegF(C, A, A + 1, A + 2);
|
|
|
|
cc.movsd(regF[A], regF[B]);
|
|
|
|
cc.movsd(regF[A + 1], regF[B + 1]);
|
|
|
|
cc.movsd(regF[A + 2], regF[B + 2]);
|
|
|
|
cc.mulsd(regF[A], rc);
|
|
|
|
cc.mulsd(regF[A + 1], rc);
|
|
|
|
cc.mulsd(regF[A + 2], rc);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitMULVF3_RK()
|
|
|
|
{
|
|
|
|
auto tmp = cc.newIntPtr();
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsd(regF[A], regF[B]);
|
|
|
|
cc.movsd(regF[A + 1], regF[B + 1]);
|
|
|
|
cc.movsd(regF[A + 2], regF[B + 2]);
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.mov(tmp, ToMemAddress(&konstf[C]));
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mulsd(regF[A], asmjit::x86::qword_ptr(tmp));
|
|
|
|
cc.mulsd(regF[A + 1], asmjit::x86::qword_ptr(tmp));
|
|
|
|
cc.mulsd(regF[A + 2], asmjit::x86::qword_ptr(tmp));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitDIVVF3_RR()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rc = CheckRegF(C, A, A + 1, A + 2);
|
|
|
|
cc.movsd(regF[A], regF[B]);
|
|
|
|
cc.movsd(regF[A + 1], regF[B + 1]);
|
|
|
|
cc.movsd(regF[A + 2], regF[B + 2]);
|
|
|
|
cc.divsd(regF[A], rc);
|
|
|
|
cc.divsd(regF[A + 1], rc);
|
|
|
|
cc.divsd(regF[A + 2], rc);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitDIVVF3_RK()
|
|
|
|
{
|
|
|
|
auto tmp = cc.newIntPtr();
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsd(regF[A], regF[B]);
|
|
|
|
cc.movsd(regF[A + 1], regF[B + 1]);
|
|
|
|
cc.movsd(regF[A + 2], regF[B + 2]);
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.mov(tmp, ToMemAddress(&konstf[C]));
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.divsd(regF[A], asmjit::x86::qword_ptr(tmp));
|
|
|
|
cc.divsd(regF[A + 1], asmjit::x86::qword_ptr(tmp));
|
|
|
|
cc.divsd(regF[A + 2], asmjit::x86::qword_ptr(tmp));
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmitLENV3()
|
|
|
|
{
|
2018-09-02 13:36:39 +00:00
|
|
|
auto rb1 = CheckRegF(B + 1, A);
|
|
|
|
auto rb2 = CheckRegF(B + 2, A);
|
2018-08-18 23:46:56 +00:00
|
|
|
auto tmp = cc.newXmmSd();
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.movsd(regF[A], regF[B]);
|
|
|
|
cc.mulsd(regF[A], regF[B]);
|
|
|
|
cc.movsd(tmp, rb1);
|
|
|
|
cc.mulsd(tmp, rb1);
|
|
|
|
cc.addsd(regF[A], tmp);
|
|
|
|
cc.movsd(tmp, rb2);
|
|
|
|
cc.mulsd(tmp, rb2);
|
|
|
|
cc.addsd(regF[A], tmp);
|
|
|
|
CallSqrt(regF[A], regF[A]);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
2018-09-02 22:44:25 +00:00
|
|
|
void EmitEQV3_R()
|
|
|
|
{
|
2018-09-11 20:48:02 +00:00
|
|
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
2018-09-02 22:47:22 +00:00
|
|
|
if (static_cast<bool>(A & CMP_APPROX)) I_FatalError("CMP_APPROX not implemented for EQV3_R.\n");
|
2018-09-02 22:44:25 +00:00
|
|
|
|
|
|
|
cc.ucomisd(regF[B], regF[C]);
|
2018-09-11 20:48:02 +00:00
|
|
|
if (check) {
|
|
|
|
cc.jp(success);
|
|
|
|
cc.jne(success);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
cc.jp(fail);
|
|
|
|
cc.jne(fail);
|
|
|
|
}
|
2018-09-02 22:44:25 +00:00
|
|
|
|
|
|
|
cc.ucomisd(regF[B + 1], regF[C + 1]);
|
2018-09-11 20:48:02 +00:00
|
|
|
if (check) {
|
|
|
|
cc.jp(success);
|
|
|
|
cc.jne(success);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
cc.jp(fail);
|
|
|
|
cc.jne(fail);
|
|
|
|
}
|
2018-09-02 22:44:25 +00:00
|
|
|
|
|
|
|
cc.ucomisd(regF[B + 2], regF[C + 2]);
|
2018-09-11 20:48:02 +00:00
|
|
|
if (check) {
|
|
|
|
cc.jp(success);
|
|
|
|
cc.je(fail);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
cc.jp(fail);
|
|
|
|
cc.jne(fail);
|
|
|
|
}
|
2018-09-02 22:44:25 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitEQV3_K()
|
|
|
|
{
|
2018-09-02 22:47:22 +00:00
|
|
|
I_FatalError("EQV3_K is not used.");
|
2018-09-02 22:44:25 +00:00
|
|
|
}
|
2018-08-18 23:46:56 +00:00
|
|
|
|
|
|
|
// Pointer math.
|
|
|
|
|
|
|
|
void EmitADDA_RR()
|
|
|
|
{
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
auto label = cc.newLabel();
|
|
|
|
|
|
|
|
cc.mov(tmp, regA[B]);
|
|
|
|
|
|
|
|
// Check if zero, the first operand is zero, if it is, don't add.
|
|
|
|
cc.cmp(tmp, 0);
|
|
|
|
cc.je(label);
|
|
|
|
|
2018-08-26 12:27:46 +00:00
|
|
|
auto tmpptr = cc.newIntPtr();
|
|
|
|
cc.mov(tmpptr, regD[C]);
|
|
|
|
cc.add(tmp, tmpptr);
|
2018-08-14 14:07:09 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.bind(label);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(regA[A], tmp);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-14 14:07:09 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitADDA_RK()
|
|
|
|
{
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
auto label = cc.newLabel();
|
2018-08-14 14:07:09 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.mov(tmp, regA[B]);
|
2018-08-14 14:07:09 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
// Check if zero, the first operand is zero, if it is, don't add.
|
|
|
|
cc.cmp(tmp, 0);
|
|
|
|
cc.je(label);
|
2018-08-14 14:07:09 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.add(tmp, konstd[C]);
|
2018-08-14 14:07:09 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.bind(label);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(regA[A], tmp);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-14 14:07:09 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitSUBA()
|
|
|
|
{
|
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, regA[B]);
|
|
|
|
cc.sub(tmp, regD[C]);
|
2018-09-02 13:36:39 +00:00
|
|
|
cc.mov(regA[A], tmp);
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-14 14:07:09 +00:00
|
|
|
|
2018-09-02 01:39:02 +00:00
|
|
|
void EmitEQA_R()
|
|
|
|
{
|
2018-09-11 20:48:02 +00:00
|
|
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
2018-09-02 01:39:02 +00:00
|
|
|
cc.cmp(regA[B], regA[C]);
|
2018-09-11 20:48:02 +00:00
|
|
|
if (check) cc.je(fail);
|
|
|
|
else cc.jne(fail);
|
2018-09-02 01:39:02 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitEQA_K()
|
|
|
|
{
|
2018-09-11 20:48:02 +00:00
|
|
|
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
|
2018-09-02 01:39:02 +00:00
|
|
|
auto tmp = cc.newIntPtr();
|
|
|
|
cc.mov(tmp, ToMemAddress(konsta[C].v));
|
|
|
|
cc.cmp(regA[B], tmp);
|
2018-09-11 20:48:02 +00:00
|
|
|
if (check) cc.je(fail);
|
|
|
|
else cc.jne(fail);
|
2018-09-02 01:39:02 +00:00
|
|
|
});
|
|
|
|
}
|
2018-08-14 14:07:09 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void Setup()
|
|
|
|
{
|
|
|
|
using namespace asmjit;
|
2018-08-14 14:07:09 +00:00
|
|
|
|
2018-08-30 17:55:00 +00:00
|
|
|
FString funcname;
|
2018-09-09 20:03:57 +00:00
|
|
|
funcname.Format("Function: %s", sfunc->PrintableName.GetChars());
|
2018-08-30 17:55:00 +00:00
|
|
|
cc.comment(funcname.GetChars(), funcname.Len());
|
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
stack = cc.newIntPtr("stack"); // VMFrameStack *stack
|
2018-09-11 15:08:51 +00:00
|
|
|
vmregs = cc.newIntPtr("vmregs"); // VMRegisters *vmregs
|
2018-08-18 23:46:56 +00:00
|
|
|
ret = cc.newIntPtr("ret"); // VMReturn *ret
|
|
|
|
numret = cc.newInt32("numret"); // int numret
|
|
|
|
exceptInfo = cc.newIntPtr("exceptinfo"); // JitExceptionInfo *exceptInfo
|
2018-08-14 14:07:09 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
cc.addFunc(FuncSignature5<int, void *, void *, void *, int, void *>());
|
|
|
|
cc.setArg(0, stack);
|
|
|
|
cc.setArg(1, vmregs);
|
|
|
|
cc.setArg(2, ret);
|
|
|
|
cc.setArg(3, numret);
|
|
|
|
cc.setArg(4, exceptInfo);
|
2018-08-14 14:07:09 +00:00
|
|
|
|
2018-09-11 23:37:30 +00:00
|
|
|
auto stack = cc.newStack(sizeof(VMReturn) * MAX_RETURNS, alignof(VMReturn));
|
|
|
|
callReturns = cc.newIntPtr("callReturns");
|
|
|
|
cc.lea(callReturns, stack);
|
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
konstd = sfunc->KonstD;
|
|
|
|
konstf = sfunc->KonstF;
|
|
|
|
konsts = sfunc->KonstS;
|
|
|
|
konsta = sfunc->KonstA;
|
2018-08-14 14:07:09 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
regD.Resize(sfunc->NumRegD);
|
|
|
|
regF.Resize(sfunc->NumRegF);
|
|
|
|
regA.Resize(sfunc->NumRegA);
|
|
|
|
//regS.Resize(sfunc->NumRegS);
|
2018-08-12 00:11:13 +00:00
|
|
|
|
2018-09-11 15:08:51 +00:00
|
|
|
frameD = cc.newIntPtr();
|
|
|
|
frameF = cc.newIntPtr();
|
|
|
|
//frameS = cc.newIntPtr();
|
|
|
|
frameA = cc.newIntPtr();
|
|
|
|
params = cc.newIntPtr();
|
|
|
|
cc.mov(frameD, x86::ptr(vmregs, offsetof(VMRegisters, d)));
|
|
|
|
cc.mov(frameF, x86::ptr(vmregs, offsetof(VMRegisters, f)));
|
|
|
|
//cc.mov(frameS, x86::ptr(vmregs, offsetof(VMRegisters, s)));
|
|
|
|
cc.mov(frameA, x86::ptr(vmregs, offsetof(VMRegisters, a)));
|
|
|
|
cc.mov(params, x86::ptr(vmregs, offsetof(VMRegisters, param)));
|
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
if (sfunc->NumRegD > 0)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < sfunc->NumRegD; i++)
|
2018-08-13 23:07:30 +00:00
|
|
|
{
|
2018-08-26 12:27:46 +00:00
|
|
|
FString regname;
|
|
|
|
regname.Format("regD%d", i);
|
|
|
|
regD[i] = cc.newInt32(regname.GetChars());
|
2018-09-11 15:08:51 +00:00
|
|
|
cc.mov(regD[i], x86::dword_ptr(frameD, i * sizeof(int32_t)));
|
2018-08-13 23:07:30 +00:00
|
|
|
}
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
if (sfunc->NumRegF > 0)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < sfunc->NumRegF; i++)
|
2018-08-13 23:07:30 +00:00
|
|
|
{
|
2018-08-26 12:27:46 +00:00
|
|
|
FString regname;
|
|
|
|
regname.Format("regF%d", i);
|
|
|
|
regF[i] = cc.newXmmSd(regname.GetChars());
|
2018-09-11 15:08:51 +00:00
|
|
|
cc.movsd(regF[i], x86::qword_ptr(frameF, i * sizeof(double)));
|
2018-08-13 23:07:30 +00:00
|
|
|
}
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
|
|
|
/*if (sfunc->NumRegS > 0)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < sfunc->NumRegS; i++)
|
2018-08-13 23:07:30 +00:00
|
|
|
{
|
2018-08-26 12:27:46 +00:00
|
|
|
FString regname;
|
|
|
|
regname.Format("regS%d", i);
|
|
|
|
regS[i] = cc.newGpd(regname.GetChars());
|
2018-08-13 23:07:30 +00:00
|
|
|
}
|
2018-08-18 23:46:56 +00:00
|
|
|
}*/
|
|
|
|
if (sfunc->NumRegA > 0)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < sfunc->NumRegA; i++)
|
2018-08-13 23:07:30 +00:00
|
|
|
{
|
2018-08-26 12:27:46 +00:00
|
|
|
FString regname;
|
|
|
|
regname.Format("regA%d", i);
|
|
|
|
regA[i] = cc.newIntPtr(regname.GetChars());
|
2018-09-11 15:08:51 +00:00
|
|
|
cc.mov(regA[i], x86::ptr(frameA, i * sizeof(void*)));
|
2018-08-13 23:07:30 +00:00
|
|
|
}
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-14 17:32:17 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
int size = sfunc->CodeSize;
|
|
|
|
labels.Resize(size);
|
|
|
|
for (int i = 0; i < size; i++) labels[i] = cc.newLabel();
|
|
|
|
}
|
2018-08-14 17:32:17 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
template <typename Func>
|
2018-09-11 20:48:02 +00:00
|
|
|
void EmitComparisonOpcode(Func jmpFunc)
|
2018-08-18 23:46:56 +00:00
|
|
|
{
|
|
|
|
using namespace asmjit;
|
2018-08-14 17:32:17 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
int i = (int)(ptrdiff_t)(pc - sfunc->Code);
|
2018-08-14 17:32:17 +00:00
|
|
|
|
2018-09-11 20:48:02 +00:00
|
|
|
auto successLabel = cc.newLabel();
|
2018-08-14 17:32:17 +00:00
|
|
|
|
2018-09-11 20:48:02 +00:00
|
|
|
auto failLabel = labels[i + 2 + JMPOFS(pc + 1)];
|
2018-09-09 18:35:37 +00:00
|
|
|
|
2018-09-11 20:48:02 +00:00
|
|
|
jmpFunc(static_cast<bool>(A & CMP_CHECK), failLabel, successLabel);
|
2018-08-14 17:32:17 +00:00
|
|
|
|
2018-09-11 20:48:02 +00:00
|
|
|
cc.bind(successLabel);
|
2018-09-09 18:35:37 +00:00
|
|
|
pc++; // This instruction uses two instruction slots - skip the next one
|
2018-08-18 23:46:56 +00:00
|
|
|
}
|
2018-08-14 17:32:17 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
static int64_t ToMemAddress(const void *d)
|
|
|
|
{
|
|
|
|
return (int64_t)(ptrdiff_t)d;
|
|
|
|
}
|
2018-08-14 17:32:17 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void CallSqrt(const asmjit::X86Xmm &a, const asmjit::X86Xmm &b)
|
|
|
|
{
|
|
|
|
using namespace asmjit;
|
|
|
|
typedef double(*FuncPtr)(double);
|
|
|
|
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(static_cast<FuncPtr>(g_sqrt))), FuncSignature1<double, double>());
|
|
|
|
call->setRet(0, a);
|
|
|
|
call->setArg(0, b);
|
|
|
|
}
|
2018-08-12 00:11:13 +00:00
|
|
|
|
- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R
- add emit code for throwing exceptions on null pointers
2018-08-31 04:57:30 +00:00
|
|
|
void EmitNullPointerThrow(int index, EVMAbortException reason)
|
|
|
|
{
|
|
|
|
auto label = cc.newLabel();
|
|
|
|
cc.test(regA[index], regA[index]);
|
|
|
|
cc.jne(label);
|
|
|
|
EmitThrowException(reason);
|
|
|
|
cc.bind(label);
|
|
|
|
}
|
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitThrowException(EVMAbortException reason)
|
|
|
|
{
|
|
|
|
using namespace asmjit;
|
2018-08-13 20:36:55 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
// Update JitExceptionInfo struct
|
|
|
|
cc.mov(x86::dword_ptr(exceptInfo, 0 * 4), (int32_t)reason);
|
|
|
|
#ifdef ASMJIT_ARCH_X64
|
|
|
|
cc.mov(x86::qword_ptr(exceptInfo, 4 * 4), ToMemAddress(pc));
|
|
|
|
#else
|
|
|
|
cc.mov(x86::dword_ptr(exceptInfo, 4 * 4), ToMemAddress(pc));
|
|
|
|
#endif
|
2018-08-12 00:11:13 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
// Return from function
|
|
|
|
X86Gp vReg = cc.newInt32();
|
|
|
|
cc.mov(vReg, 0);
|
|
|
|
cc.ret(vReg);
|
|
|
|
}
|
2018-08-15 02:08:09 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
void EmitThrowException(EVMAbortException reason, asmjit::X86Gp arg1)
|
|
|
|
{
|
|
|
|
using namespace asmjit;
|
2018-08-15 02:08:09 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
// Update JitExceptionInfo struct
|
|
|
|
cc.mov(x86::dword_ptr(exceptInfo, 0 * 4), (int32_t)reason);
|
|
|
|
cc.mov(x86::dword_ptr(exceptInfo, 1 * 4), arg1);
|
|
|
|
#ifdef ASMJIT_ARCH_X64
|
|
|
|
cc.mov(x86::qword_ptr(exceptInfo, 4 * 4), ToMemAddress(pc));
|
|
|
|
#else
|
|
|
|
cc.mov(x86::dword_ptr(exceptInfo, 4 * 4), ToMemAddress(pc));
|
|
|
|
#endif
|
2018-08-15 02:08:09 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
// Return from function
|
|
|
|
X86Gp vReg = cc.newInt32();
|
|
|
|
cc.mov(vReg, 0);
|
|
|
|
cc.ret(vReg);
|
|
|
|
}
|
2018-08-15 02:08:09 +00:00
|
|
|
|
2018-09-02 13:36:39 +00:00
|
|
|
asmjit::X86Gp CheckRegD(int r0, int r1)
|
|
|
|
{
|
|
|
|
if (r0 != r1)
|
|
|
|
{
|
|
|
|
return regD[r0];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
auto copy = cc.newInt32();
|
|
|
|
cc.mov(copy, regD[r0]);
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
asmjit::X86Xmm CheckRegF(int r0, int r1)
|
|
|
|
{
|
|
|
|
if (r0 != r1)
|
|
|
|
{
|
|
|
|
return regF[r0];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
auto copy = cc.newXmm();
|
|
|
|
cc.movsd(copy, regF[r0]);
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
asmjit::X86Xmm CheckRegF(int r0, int r1, int r2)
|
|
|
|
{
|
|
|
|
if (r0 != r1 && r0 != r2)
|
|
|
|
{
|
|
|
|
return regF[r0];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
auto copy = cc.newXmm();
|
|
|
|
cc.movsd(copy, regF[r0]);
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
asmjit::X86Xmm CheckRegF(int r0, int r1, int r2, int r3)
|
|
|
|
{
|
|
|
|
if (r0 != r1 && r0 != r2 && r0 != r3)
|
|
|
|
{
|
|
|
|
return regF[r0];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
auto copy = cc.newXmm();
|
|
|
|
cc.movsd(copy, regF[r0]);
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
asmjit::X86Gp CheckRegA(int r0, int r1)
|
|
|
|
{
|
|
|
|
if (r0 != r1)
|
|
|
|
{
|
|
|
|
return regA[r0];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
auto copy = cc.newIntPtr();
|
|
|
|
cc.mov(copy, regA[r0]);
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
asmjit::X86Compiler cc;
|
|
|
|
VMScriptFunction *sfunc;
|
2018-08-15 02:08:09 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
asmjit::X86Gp stack;
|
|
|
|
asmjit::X86Gp vmregs;
|
|
|
|
asmjit::X86Gp ret;
|
|
|
|
asmjit::X86Gp numret;
|
|
|
|
asmjit::X86Gp exceptInfo;
|
2018-08-12 22:15:42 +00:00
|
|
|
|
2018-09-11 15:08:51 +00:00
|
|
|
asmjit::X86Gp frameD;
|
|
|
|
asmjit::X86Gp frameF;
|
|
|
|
asmjit::X86Gp frameA;
|
|
|
|
asmjit::X86Gp params;
|
2018-09-12 19:58:31 +00:00
|
|
|
int NumParam = 0; // Actually part of vmframe (f->NumParam), but nobody seems to read that?
|
|
|
|
TArray<const VMOP *> ParamOpcodes;
|
2018-09-11 23:37:30 +00:00
|
|
|
asmjit::X86Gp callReturns;
|
2018-09-11 15:08:51 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
const int *konstd;
|
|
|
|
const double *konstf;
|
|
|
|
const FString *konsts;
|
|
|
|
const FVoidObj *konsta;
|
2018-08-15 02:08:09 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
TArray<asmjit::X86Gp> regD;
|
|
|
|
TArray<asmjit::X86Xmm> regF;
|
|
|
|
TArray<asmjit::X86Gp> regA;
|
|
|
|
//TArray<asmjit::X86Gp> regS;
|
2018-08-15 02:08:09 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
TArray<asmjit::Label> labels;
|
2018-08-15 02:08:09 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
const VMOP *pc;
|
|
|
|
VM_UBYTE op;
|
|
|
|
};
|
2018-08-15 02:08:09 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
class AsmJitException : public std::exception
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
AsmJitException(asmjit::Error error, const char *message) noexcept : error(error), message(message)
|
|
|
|
{
|
|
|
|
}
|
2018-08-15 02:08:09 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
const char* what() const noexcept override
|
|
|
|
{
|
|
|
|
return message.GetChars();
|
|
|
|
}
|
2018-08-12 22:15:42 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
asmjit::Error error;
|
|
|
|
FString message;
|
|
|
|
};
|
2018-08-12 22:15:42 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
class ThrowingErrorHandler : public asmjit::ErrorHandler
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
bool handleError(asmjit::Error err, const char *message, asmjit::CodeEmitter *origin) override
|
|
|
|
{
|
|
|
|
throw AsmJitException(err, message);
|
|
|
|
}
|
|
|
|
};
|
2018-08-12 00:11:13 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
static asmjit::JitRuntime *jit;
|
|
|
|
static int jitRefCount = 0;
|
|
|
|
|
|
|
|
asmjit::JitRuntime *JitGetRuntime()
|
|
|
|
{
|
|
|
|
if (!jit)
|
|
|
|
jit = new asmjit::JitRuntime;
|
|
|
|
jitRefCount++;
|
|
|
|
return jit;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JitCleanUp(VMScriptFunction *func)
|
|
|
|
{
|
|
|
|
jitRefCount--;
|
|
|
|
if (jitRefCount == 0)
|
|
|
|
{
|
|
|
|
delete jit;
|
|
|
|
jit = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-30 17:55:00 +00:00
|
|
|
static void OutputJitLog(const asmjit::StringLogger &logger)
|
|
|
|
{
|
|
|
|
// Write line by line since I_FatalError seems to cut off long strings
|
|
|
|
const char *pos = logger.getString();
|
|
|
|
const char *end = pos;
|
|
|
|
while (*end)
|
|
|
|
{
|
|
|
|
if (*end == '\n')
|
|
|
|
{
|
|
|
|
FString substr(pos, (int)(ptrdiff_t)(end - pos));
|
|
|
|
Printf("%s\n", substr.GetChars());
|
|
|
|
pos = end + 1;
|
|
|
|
}
|
|
|
|
end++;
|
|
|
|
}
|
|
|
|
if (pos != end)
|
|
|
|
Printf("%s\n", pos);
|
|
|
|
}
|
|
|
|
|
2018-09-09 20:42:59 +00:00
|
|
|
//#define DEBUG_JIT
|
2018-08-30 17:55:00 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
JitFuncPtr JitCompile(VMScriptFunction *sfunc)
|
|
|
|
{
|
2018-08-30 17:55:00 +00:00
|
|
|
#if defined(DEBUG_JIT)
|
2018-09-09 21:21:47 +00:00
|
|
|
if (strcmp(sfunc->PrintableName.GetChars(), "Key.ShouldStay") != 0)
|
2018-08-18 23:46:56 +00:00
|
|
|
return nullptr;
|
|
|
|
#else
|
|
|
|
if (!JitCompiler::CanJit(sfunc))
|
|
|
|
return nullptr;
|
|
|
|
#endif
|
|
|
|
|
2018-09-09 20:42:59 +00:00
|
|
|
//Printf("Jitting function: %s\n", sfunc->PrintableName.GetChars());
|
2018-09-09 20:03:57 +00:00
|
|
|
|
2018-08-18 23:46:56 +00:00
|
|
|
using namespace asmjit;
|
2018-08-26 12:27:46 +00:00
|
|
|
StringLogger logger;
|
2018-08-18 23:46:56 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
auto *jit = JitGetRuntime();
|
|
|
|
|
|
|
|
ThrowingErrorHandler errorHandler;
|
|
|
|
CodeHolder code;
|
|
|
|
code.init(jit->getCodeInfo());
|
|
|
|
code.setErrorHandler(&errorHandler);
|
2018-08-26 12:27:46 +00:00
|
|
|
code.setLogger(&logger);
|
2018-08-18 23:46:56 +00:00
|
|
|
|
|
|
|
JitCompiler compiler(&code, sfunc);
|
|
|
|
compiler.Codegen();
|
2018-08-12 00:11:13 +00:00
|
|
|
|
|
|
|
JitFuncPtr fn = nullptr;
|
2018-08-18 15:50:47 +00:00
|
|
|
Error err = jit->add(&fn, &code);
|
2018-08-12 00:11:13 +00:00
|
|
|
if (err)
|
|
|
|
I_FatalError("JitRuntime::add failed: %d", err);
|
2018-08-30 17:55:00 +00:00
|
|
|
|
|
|
|
#if defined(DEBUG_JIT)
|
|
|
|
OutputJitLog(logger);
|
|
|
|
#endif
|
|
|
|
|
2018-08-12 00:11:13 +00:00
|
|
|
return fn;
|
|
|
|
}
|
|
|
|
catch (const std::exception &e)
|
|
|
|
{
|
2018-08-30 17:55:00 +00:00
|
|
|
OutputJitLog(logger);
|
2018-08-26 12:27:46 +00:00
|
|
|
I_FatalError("Unexpected JIT error: %s\n", e.what());
|
2018-08-12 00:11:13 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|