mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
refactor Assembler.cpp ; passing acceptance on mac
This commit is contained in:
parent
9ce451ef43
commit
2cc651e33b
@ -659,60 +659,6 @@ namespace nanojit
|
|||||||
_allocator.addFree(r);
|
_allocator.addFree(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Assembler::asm_cmp(LIns *cond)
|
|
||||||
{
|
|
||||||
LOpcode condop = cond->opcode();
|
|
||||||
|
|
||||||
// LIR_ov and LIR_cs recycle the flags set by arithmetic ops
|
|
||||||
if ((condop == LIR_ov) || (condop == LIR_cs))
|
|
||||||
return;
|
|
||||||
|
|
||||||
LInsp lhs = cond->oprnd1();
|
|
||||||
LInsp rhs = cond->oprnd2();
|
|
||||||
Reservation *rA, *rB;
|
|
||||||
|
|
||||||
NanoAssert((!lhs->isQuad() && !rhs->isQuad()) || (lhs->isQuad() && rhs->isQuad()));
|
|
||||||
|
|
||||||
// Not supported yet.
|
|
||||||
#if !defined NANOJIT_64BIT
|
|
||||||
NanoAssert(!lhs->isQuad() && !rhs->isQuad());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ready to issue the compare
|
|
||||||
if (rhs->isconst())
|
|
||||||
{
|
|
||||||
int c = rhs->constval();
|
|
||||||
if (c == 0 && cond->isop(LIR_eq)) {
|
|
||||||
Register r = findRegFor(lhs, GpRegs);
|
|
||||||
if (rhs->isQuad()) {
|
|
||||||
#if defined NANOJIT_64BIT
|
|
||||||
TESTQ(r, r);
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
TEST(r,r);
|
|
||||||
}
|
|
||||||
// No 64-bit immediates so fall-back to below
|
|
||||||
}
|
|
||||||
else if (!rhs->isQuad()) {
|
|
||||||
Register r = getBaseReg(lhs, c, GpRegs);
|
|
||||||
CMPi(r, c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
findRegFor2(GpRegs, lhs, rA, rhs, rB);
|
|
||||||
Register ra = rA->reg;
|
|
||||||
Register rb = rB->reg;
|
|
||||||
if (rhs->isQuad()) {
|
|
||||||
#if defined NANOJIT_64BIT
|
|
||||||
CMPQ(ra, rb);
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
CMP(ra, rb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Assembler::patch(GuardRecord *lr)
|
void Assembler::patch(GuardRecord *lr)
|
||||||
{
|
{
|
||||||
Fragment *frag = lr->target;
|
Fragment *frag = lr->target;
|
||||||
@ -1116,19 +1062,15 @@ namespace nanojit
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LIR_short:
|
case LIR_short:
|
||||||
|
{
|
||||||
|
countlir_imm();
|
||||||
|
asm_short(ins);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case LIR_int:
|
case LIR_int:
|
||||||
{
|
{
|
||||||
countlir_imm();
|
countlir_imm();
|
||||||
Register rr = prepResultReg(ins, GpRegs);
|
asm_int(ins);
|
||||||
int32_t val;
|
|
||||||
if (op == LIR_int)
|
|
||||||
val = ins->imm32();
|
|
||||||
else
|
|
||||||
val = ins->imm16();
|
|
||||||
if (val == 0)
|
|
||||||
XOR(rr,rr);
|
|
||||||
else
|
|
||||||
LDi(rr, val);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LIR_quad:
|
case LIR_quad:
|
||||||
@ -1150,132 +1092,36 @@ namespace nanojit
|
|||||||
case LIR_param:
|
case LIR_param:
|
||||||
{
|
{
|
||||||
countlir_param();
|
countlir_param();
|
||||||
uint32_t a = ins->imm8();
|
asm_param(ins);
|
||||||
uint32_t kind = ins->imm8b();
|
|
||||||
if (kind == 0) {
|
|
||||||
// ordinary param
|
|
||||||
AbiKind abi = _thisfrag->lirbuf->abi;
|
|
||||||
uint32_t abi_regcount = abi == ABI_FASTCALL ? 2 : abi == ABI_THISCALL ? 1 : 0;
|
|
||||||
if (a < abi_regcount) {
|
|
||||||
// incoming arg in register
|
|
||||||
prepResultReg(ins, rmask(argRegs[a]));
|
|
||||||
} else {
|
|
||||||
// incoming arg is on stack, and EBP points nearby (see genPrologue)
|
|
||||||
Register r = prepResultReg(ins, GpRegs);
|
|
||||||
int d = (a - abi_regcount) * sizeof(intptr_t) + 8;
|
|
||||||
LD(r, d, FP);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// saved param
|
|
||||||
prepResultReg(ins, rmask(savedRegs[a]));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LIR_qlo:
|
case LIR_qlo:
|
||||||
{
|
{
|
||||||
countlir_qlo();
|
countlir_qlo();
|
||||||
LIns *q = ins->oprnd1();
|
asm_qlo(ins);
|
||||||
|
|
||||||
if (!asm_qlo(ins, q))
|
|
||||||
{
|
|
||||||
Register rr = prepResultReg(ins, GpRegs);
|
|
||||||
int d = findMemFor(q);
|
|
||||||
LD(rr, d, FP);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LIR_qhi:
|
case LIR_qhi:
|
||||||
{
|
{
|
||||||
countlir_qhi();
|
countlir_qhi();
|
||||||
Register rr = prepResultReg(ins, GpRegs);
|
asm_qhi(ins);
|
||||||
LIns *q = ins->oprnd1();
|
|
||||||
int d = findMemFor(q);
|
|
||||||
LD(rr, d+4, FP);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case LIR_qcmov:
|
case LIR_qcmov:
|
||||||
case LIR_cmov:
|
case LIR_cmov:
|
||||||
{
|
{
|
||||||
countlir_cmov();
|
countlir_cmov();
|
||||||
LIns* condval = ins->oprnd1();
|
asm_cmov(ins);
|
||||||
NanoAssert(condval->isCmp());
|
|
||||||
|
|
||||||
LIns* values = ins->oprnd2();
|
|
||||||
|
|
||||||
NanoAssert(values->opcode() == LIR_2);
|
|
||||||
LIns* iftrue = values->oprnd1();
|
|
||||||
LIns* iffalse = values->oprnd2();
|
|
||||||
|
|
||||||
NanoAssert(op == LIR_qcmov || (!iftrue->isQuad() && !iffalse->isQuad()));
|
|
||||||
|
|
||||||
const Register rr = prepResultReg(ins, GpRegs);
|
|
||||||
|
|
||||||
// this code assumes that neither LD nor MR nor MRcc set any of the condition flags.
|
|
||||||
// (This is true on Intel, is it true on all architectures?)
|
|
||||||
const Register iffalsereg = findRegFor(iffalse, GpRegs & ~rmask(rr));
|
|
||||||
if (op == LIR_cmov) {
|
|
||||||
switch (condval->opcode())
|
|
||||||
{
|
|
||||||
// note that these are all opposites...
|
|
||||||
case LIR_eq: MRNE(rr, iffalsereg); break;
|
|
||||||
case LIR_ov: MRNO(rr, iffalsereg); break;
|
|
||||||
case LIR_cs: MRNC(rr, iffalsereg); break;
|
|
||||||
case LIR_lt: MRGE(rr, iffalsereg); break;
|
|
||||||
case LIR_le: MRG(rr, iffalsereg); break;
|
|
||||||
case LIR_gt: MRLE(rr, iffalsereg); break;
|
|
||||||
case LIR_ge: MRL(rr, iffalsereg); break;
|
|
||||||
case LIR_ult: MRAE(rr, iffalsereg); break;
|
|
||||||
case LIR_ule: MRA(rr, iffalsereg); break;
|
|
||||||
case LIR_ugt: MRBE(rr, iffalsereg); break;
|
|
||||||
case LIR_uge: MRB(rr, iffalsereg); break;
|
|
||||||
debug_only( default: NanoAssert(0); break; )
|
|
||||||
}
|
|
||||||
} else if (op == LIR_qcmov) {
|
|
||||||
#if !defined NANOJIT_64BIT
|
|
||||||
NanoAssert(0);
|
|
||||||
#else
|
|
||||||
switch (condval->opcode())
|
|
||||||
{
|
|
||||||
// note that these are all opposites...
|
|
||||||
case LIR_eq: MRQNE(rr, iffalsereg); break;
|
|
||||||
case LIR_ov: MRQNO(rr, iffalsereg); break;
|
|
||||||
case LIR_cs: MRQNC(rr, iffalsereg); break;
|
|
||||||
case LIR_lt: MRQGE(rr, iffalsereg); break;
|
|
||||||
case LIR_le: MRQG(rr, iffalsereg); break;
|
|
||||||
case LIR_gt: MRQLE(rr, iffalsereg); break;
|
|
||||||
case LIR_ge: MRQL(rr, iffalsereg); break;
|
|
||||||
case LIR_ult: MRQAE(rr, iffalsereg); break;
|
|
||||||
case LIR_ule: MRQA(rr, iffalsereg); break;
|
|
||||||
case LIR_ugt: MRQBE(rr, iffalsereg); break;
|
|
||||||
case LIR_uge: MRQB(rr, iffalsereg); break;
|
|
||||||
debug_only( default: NanoAssert(0); break; )
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
/*const Register iftruereg =*/ findSpecificRegFor(iftrue, rr);
|
|
||||||
asm_cmp(condval);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case LIR_ld:
|
case LIR_ld:
|
||||||
case LIR_ldc:
|
case LIR_ldc:
|
||||||
case LIR_ldcb:
|
case LIR_ldcb:
|
||||||
{
|
{
|
||||||
countlir_ld();
|
countlir_ld();
|
||||||
LIns* base = ins->oprnd1();
|
asm_ld(ins);
|
||||||
LIns* disp = ins->oprnd2();
|
|
||||||
Register rr = prepResultReg(ins, GpRegs);
|
|
||||||
int d = disp->constval();
|
|
||||||
Register ra = getBaseReg(base, d, GpRegs);
|
|
||||||
if (op == LIR_ldcb)
|
|
||||||
LD8Z(rr, d, ra);
|
|
||||||
else
|
|
||||||
LD(rr, d, ra);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case LIR_ldq:
|
case LIR_ldq:
|
||||||
case LIR_ldqc:
|
case LIR_ldqc:
|
||||||
{
|
{
|
||||||
@ -1283,31 +1129,13 @@ namespace nanojit
|
|||||||
asm_load64(ins);
|
asm_load64(ins);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case LIR_neg:
|
case LIR_neg:
|
||||||
case LIR_not:
|
case LIR_not:
|
||||||
{
|
{
|
||||||
countlir_alu();
|
countlir_alu();
|
||||||
Register rr = prepResultReg(ins, GpRegs);
|
asm_neg_not(ins);
|
||||||
|
|
||||||
LIns* lhs = ins->oprnd1();
|
|
||||||
Reservation *rA = getresv(lhs);
|
|
||||||
// if this is last use of lhs in reg, we can re-use result reg
|
|
||||||
Register ra;
|
|
||||||
if (rA == 0 || (ra=rA->reg) == UnknownReg)
|
|
||||||
ra = findSpecificRegFor(lhs, rr);
|
|
||||||
// else, rA already has a register assigned.
|
|
||||||
|
|
||||||
if (op == LIR_not)
|
|
||||||
NOT(rr);
|
|
||||||
else
|
|
||||||
NEG(rr);
|
|
||||||
|
|
||||||
if ( rr != ra )
|
|
||||||
MR(rr,ra);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case LIR_qjoin:
|
case LIR_qjoin:
|
||||||
{
|
{
|
||||||
countlir_qjoin();
|
countlir_qjoin();
|
||||||
@ -1338,115 +1166,7 @@ namespace nanojit
|
|||||||
case LIR_ush:
|
case LIR_ush:
|
||||||
{
|
{
|
||||||
countlir_alu();
|
countlir_alu();
|
||||||
LInsp lhs = ins->oprnd1();
|
asm_arith(ins);
|
||||||
LInsp rhs = ins->oprnd2();
|
|
||||||
|
|
||||||
Register rb = UnknownReg;
|
|
||||||
RegisterMask allow = GpRegs;
|
|
||||||
bool forceReg = (op == LIR_mul || !rhs->isconst());
|
|
||||||
|
|
||||||
#ifdef NANOJIT_ARM
|
|
||||||
// Arm can't do an immediate op with immediates
|
|
||||||
// outside of +/-255 (for AND) r outside of
|
|
||||||
// 0..255 for others.
|
|
||||||
if (!forceReg)
|
|
||||||
{
|
|
||||||
if (rhs->isconst() && !isU8(rhs->constval()))
|
|
||||||
forceReg = true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (lhs != rhs && forceReg)
|
|
||||||
{
|
|
||||||
if ((rb = asm_binop_rhs_reg(ins)) == UnknownReg) {
|
|
||||||
rb = findRegFor(rhs, allow);
|
|
||||||
}
|
|
||||||
allow &= ~rmask(rb);
|
|
||||||
}
|
|
||||||
else if ((op == LIR_add||op == LIR_addp) && lhs->isop(LIR_alloc) && rhs->isconst()) {
|
|
||||||
// add alloc+const, use lea
|
|
||||||
Register rr = prepResultReg(ins, allow);
|
|
||||||
int d = findMemFor(lhs) + rhs->constval();
|
|
||||||
LEA(rr, d, FP);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Register rr = prepResultReg(ins, allow);
|
|
||||||
Reservation* rA = getresv(lhs);
|
|
||||||
Register ra;
|
|
||||||
// if this is last use of lhs in reg, we can re-use result reg
|
|
||||||
if (rA == 0 || (ra = rA->reg) == UnknownReg)
|
|
||||||
ra = findSpecificRegFor(lhs, rr);
|
|
||||||
// else, rA already has a register assigned.
|
|
||||||
|
|
||||||
if (forceReg)
|
|
||||||
{
|
|
||||||
if (lhs == rhs)
|
|
||||||
rb = ra;
|
|
||||||
|
|
||||||
if (op == LIR_add || op == LIR_addp)
|
|
||||||
ADD(rr, rb);
|
|
||||||
else if (op == LIR_sub)
|
|
||||||
SUB(rr, rb);
|
|
||||||
else if (op == LIR_mul)
|
|
||||||
MUL(rr, rb);
|
|
||||||
else if (op == LIR_and)
|
|
||||||
AND(rr, rb);
|
|
||||||
else if (op == LIR_or)
|
|
||||||
OR(rr, rb);
|
|
||||||
else if (op == LIR_xor)
|
|
||||||
XOR(rr, rb);
|
|
||||||
else if (op == LIR_lsh)
|
|
||||||
SHL(rr, rb);
|
|
||||||
else if (op == LIR_rsh)
|
|
||||||
SAR(rr, rb);
|
|
||||||
else if (op == LIR_ush)
|
|
||||||
SHR(rr, rb);
|
|
||||||
else
|
|
||||||
NanoAssertMsg(0, "Unsupported");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int c = rhs->constval();
|
|
||||||
if (op == LIR_add || op == LIR_addp) {
|
|
||||||
#ifdef NANOJIT_IA32_TODO
|
|
||||||
if (ra != rr) {
|
|
||||||
// this doesn't set cc's, only use it when cc's not required.
|
|
||||||
LEA(rr, c, ra);
|
|
||||||
ra = rr; // suppress mov
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
ADDi(rr, c);
|
|
||||||
}
|
|
||||||
} else if (op == LIR_sub) {
|
|
||||||
#ifdef NANOJIT_IA32
|
|
||||||
if (ra != rr) {
|
|
||||||
LEA(rr, -c, ra);
|
|
||||||
ra = rr;
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
SUBi(rr, c);
|
|
||||||
}
|
|
||||||
} else if (op == LIR_and)
|
|
||||||
ANDi(rr, c);
|
|
||||||
else if (op == LIR_or)
|
|
||||||
ORi(rr, c);
|
|
||||||
else if (op == LIR_xor)
|
|
||||||
XORi(rr, c);
|
|
||||||
else if (op == LIR_lsh)
|
|
||||||
SHLi(rr, c);
|
|
||||||
else if (op == LIR_rsh)
|
|
||||||
SARi(rr, c);
|
|
||||||
else if (op == LIR_ush)
|
|
||||||
SHRi(rr, c);
|
|
||||||
else
|
|
||||||
NanoAssertMsg(0, "Unsupported");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( rr != ra )
|
|
||||||
MR(rr,ra);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#ifndef NJ_SOFTFLOAT
|
#ifndef NJ_SOFTFLOAT
|
||||||
@ -1622,28 +1342,10 @@ namespace nanojit
|
|||||||
case LIR_loop:
|
case LIR_loop:
|
||||||
{
|
{
|
||||||
countlir_loop();
|
countlir_loop();
|
||||||
JMP_long_placeholder(); // jump to SOT
|
asm_loop(ins, loopJumps);
|
||||||
verbose_only( if (_verbose && _outputCache) { _outputCache->removeLast(); outputf(" jmp SOT"); } );
|
|
||||||
|
|
||||||
loopJumps.add(_nIns);
|
|
||||||
|
|
||||||
#ifdef NJ_VERBOSE
|
|
||||||
// branching from this frag to ourself.
|
|
||||||
if (_frago->core()->config.show_stats)
|
|
||||||
#if defined NANOJIT_AMD64
|
|
||||||
LDQi(argRegs[1], intptr_t((Fragment*)_thisfrag));
|
|
||||||
#else
|
|
||||||
LDi(argRegs[1], int((Fragment*)_thisfrag));
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
assignSavedParams();
|
|
||||||
|
|
||||||
// restore first parameter, the only one we use
|
|
||||||
LInsp state = _thisfrag->lirbuf->state;
|
|
||||||
findSpecificRegFor(state, argRegs[state->imm8()]);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NJ_SOFTFLOAT
|
#ifndef NJ_SOFTFLOAT
|
||||||
case LIR_feq:
|
case LIR_feq:
|
||||||
case LIR_fle:
|
case LIR_fle:
|
||||||
@ -1652,17 +1354,7 @@ namespace nanojit
|
|||||||
case LIR_fge:
|
case LIR_fge:
|
||||||
{
|
{
|
||||||
countlir_fpu();
|
countlir_fpu();
|
||||||
// only want certain regs
|
asm_fcond(ins);
|
||||||
Register r = prepResultReg(ins, AllowableFlagRegs);
|
|
||||||
asm_setcc(r, ins);
|
|
||||||
#ifdef NJ_ARM_VFP
|
|
||||||
SETE(r);
|
|
||||||
#else
|
|
||||||
// SETcc only sets low 8 bits, so extend
|
|
||||||
MOVZX8(r,r);
|
|
||||||
SETNP(r);
|
|
||||||
#endif
|
|
||||||
asm_fcmp(ins);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -1679,36 +1371,10 @@ namespace nanojit
|
|||||||
case LIR_uge:
|
case LIR_uge:
|
||||||
{
|
{
|
||||||
countlir_alu();
|
countlir_alu();
|
||||||
// only want certain regs
|
asm_cond(ins);
|
||||||
Register r = prepResultReg(ins, AllowableFlagRegs);
|
|
||||||
// SETcc only sets low 8 bits, so extend
|
|
||||||
MOVZX8(r,r);
|
|
||||||
if (op == LIR_eq)
|
|
||||||
SETE(r);
|
|
||||||
else if (op == LIR_ov)
|
|
||||||
SETO(r);
|
|
||||||
else if (op == LIR_cs)
|
|
||||||
SETC(r);
|
|
||||||
else if (op == LIR_lt)
|
|
||||||
SETL(r);
|
|
||||||
else if (op == LIR_le)
|
|
||||||
SETLE(r);
|
|
||||||
else if (op == LIR_gt)
|
|
||||||
SETG(r);
|
|
||||||
else if (op == LIR_ge)
|
|
||||||
SETGE(r);
|
|
||||||
else if (op == LIR_ult)
|
|
||||||
SETB(r);
|
|
||||||
else if (op == LIR_ule)
|
|
||||||
SETBE(r);
|
|
||||||
else if (op == LIR_ugt)
|
|
||||||
SETA(r);
|
|
||||||
else // if (op == LIR_uge)
|
|
||||||
SETAE(r);
|
|
||||||
asm_cmp(ins);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NJ_SOFTFLOAT
|
#ifndef NJ_SOFTFLOAT
|
||||||
case LIR_fcall:
|
case LIR_fcall:
|
||||||
case LIR_fcalli:
|
case LIR_fcalli:
|
||||||
@ -1750,73 +1416,6 @@ namespace nanojit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NIns* Assembler::asm_branch(bool branchOnFalse, LInsp cond, NIns* targ)
|
|
||||||
{
|
|
||||||
NIns* at = 0;
|
|
||||||
LOpcode condop = cond->opcode();
|
|
||||||
NanoAssert(cond->isCond());
|
|
||||||
#ifndef NJ_SOFTFLOAT
|
|
||||||
if (condop >= LIR_feq && condop <= LIR_fge)
|
|
||||||
{
|
|
||||||
return asm_jmpcc(branchOnFalse, cond, targ);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// produce the branch
|
|
||||||
if (branchOnFalse)
|
|
||||||
{
|
|
||||||
if (condop == LIR_eq)
|
|
||||||
JNE(targ);
|
|
||||||
else if (condop == LIR_ov)
|
|
||||||
JNO(targ);
|
|
||||||
else if (condop == LIR_cs)
|
|
||||||
JNC(targ);
|
|
||||||
else if (condop == LIR_lt)
|
|
||||||
JNL(targ);
|
|
||||||
else if (condop == LIR_le)
|
|
||||||
JNLE(targ);
|
|
||||||
else if (condop == LIR_gt)
|
|
||||||
JNG(targ);
|
|
||||||
else if (condop == LIR_ge)
|
|
||||||
JNGE(targ);
|
|
||||||
else if (condop == LIR_ult)
|
|
||||||
JNB(targ);
|
|
||||||
else if (condop == LIR_ule)
|
|
||||||
JNBE(targ);
|
|
||||||
else if (condop == LIR_ugt)
|
|
||||||
JNA(targ);
|
|
||||||
else //if (condop == LIR_uge)
|
|
||||||
JNAE(targ);
|
|
||||||
}
|
|
||||||
else // op == LIR_xt
|
|
||||||
{
|
|
||||||
if (condop == LIR_eq)
|
|
||||||
JE(targ);
|
|
||||||
else if (condop == LIR_ov)
|
|
||||||
JO(targ);
|
|
||||||
else if (condop == LIR_cs)
|
|
||||||
JC(targ);
|
|
||||||
else if (condop == LIR_lt)
|
|
||||||
JL(targ);
|
|
||||||
else if (condop == LIR_le)
|
|
||||||
JLE(targ);
|
|
||||||
else if (condop == LIR_gt)
|
|
||||||
JG(targ);
|
|
||||||
else if (condop == LIR_ge)
|
|
||||||
JGE(targ);
|
|
||||||
else if (condop == LIR_ult)
|
|
||||||
JB(targ);
|
|
||||||
else if (condop == LIR_ule)
|
|
||||||
JBE(targ);
|
|
||||||
else if (condop == LIR_ugt)
|
|
||||||
JA(targ);
|
|
||||||
else //if (condop == LIR_uge)
|
|
||||||
JAE(targ);
|
|
||||||
}
|
|
||||||
at = _nIns;
|
|
||||||
asm_cmp(cond);
|
|
||||||
return at;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Assembler::assignSavedParams()
|
void Assembler::assignSavedParams()
|
||||||
{
|
{
|
||||||
// restore saved regs
|
// restore saved regs
|
||||||
@ -1867,6 +1466,7 @@ namespace nanojit
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
#ifdef NANOJIT_ARM
|
#ifdef NANOJIT_ARM
|
||||||
|
// @todo Why is there here?!? This routine should be indep. of platform
|
||||||
verbose_only(
|
verbose_only(
|
||||||
if (_verbose) {
|
if (_verbose) {
|
||||||
char* s = &outline[0];
|
char* s = &outline[0];
|
||||||
|
@ -296,7 +296,18 @@ namespace nanojit
|
|||||||
void asm_pusharg(LInsp p);
|
void asm_pusharg(LInsp p);
|
||||||
NIns* asm_adjustBranch(NIns* at, NIns* target);
|
NIns* asm_adjustBranch(NIns* at, NIns* target);
|
||||||
void asm_quad(LInsp i);
|
void asm_quad(LInsp i);
|
||||||
bool asm_qlo(LInsp ins, LInsp q);
|
void asm_loop(LInsp i, NInsList& loopJumps);
|
||||||
|
void asm_fcond(LInsp i);
|
||||||
|
void asm_cond(LInsp i);
|
||||||
|
void asm_arith(LInsp i);
|
||||||
|
void asm_neg_not(LInsp i);
|
||||||
|
void asm_ld(LInsp i);
|
||||||
|
void asm_cmov(LInsp i);
|
||||||
|
void asm_param(LInsp i);
|
||||||
|
void asm_int(LInsp i);
|
||||||
|
void asm_short(LInsp i);
|
||||||
|
void asm_qlo(LInsp i);
|
||||||
|
void asm_qhi(LInsp i);
|
||||||
void asm_fneg(LInsp ins);
|
void asm_fneg(LInsp ins);
|
||||||
void asm_fop(LInsp ins);
|
void asm_fop(LInsp ins);
|
||||||
void asm_i2f(LInsp ins);
|
void asm_i2f(LInsp ins);
|
||||||
|
@ -253,6 +253,480 @@ Assembler::asm_call(LInsp ins)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NIns* Assembler::asm_branch(bool branchOnFalse, LInsp cond, NIns* targ)
|
||||||
|
{
|
||||||
|
NIns* at = 0;
|
||||||
|
LOpcode condop = cond->opcode();
|
||||||
|
NanoAssert(cond->isCond());
|
||||||
|
#ifndef NJ_SOFTFLOAT
|
||||||
|
if (condop >= LIR_feq && condop <= LIR_fge)
|
||||||
|
{
|
||||||
|
return asm_jmpcc(branchOnFalse, cond, targ);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// produce the branch
|
||||||
|
if (branchOnFalse)
|
||||||
|
{
|
||||||
|
if (condop == LIR_eq)
|
||||||
|
JNE(targ);
|
||||||
|
else if (condop == LIR_ov)
|
||||||
|
JNO(targ);
|
||||||
|
else if (condop == LIR_cs)
|
||||||
|
JNC(targ);
|
||||||
|
else if (condop == LIR_lt)
|
||||||
|
JNL(targ);
|
||||||
|
else if (condop == LIR_le)
|
||||||
|
JNLE(targ);
|
||||||
|
else if (condop == LIR_gt)
|
||||||
|
JNG(targ);
|
||||||
|
else if (condop == LIR_ge)
|
||||||
|
JNGE(targ);
|
||||||
|
else if (condop == LIR_ult)
|
||||||
|
JNB(targ);
|
||||||
|
else if (condop == LIR_ule)
|
||||||
|
JNBE(targ);
|
||||||
|
else if (condop == LIR_ugt)
|
||||||
|
JNA(targ);
|
||||||
|
else //if (condop == LIR_uge)
|
||||||
|
JNAE(targ);
|
||||||
|
}
|
||||||
|
else // op == LIR_xt
|
||||||
|
{
|
||||||
|
if (condop == LIR_eq)
|
||||||
|
JE(targ);
|
||||||
|
else if (condop == LIR_ov)
|
||||||
|
JO(targ);
|
||||||
|
else if (condop == LIR_cs)
|
||||||
|
JC(targ);
|
||||||
|
else if (condop == LIR_lt)
|
||||||
|
JL(targ);
|
||||||
|
else if (condop == LIR_le)
|
||||||
|
JLE(targ);
|
||||||
|
else if (condop == LIR_gt)
|
||||||
|
JG(targ);
|
||||||
|
else if (condop == LIR_ge)
|
||||||
|
JGE(targ);
|
||||||
|
else if (condop == LIR_ult)
|
||||||
|
JB(targ);
|
||||||
|
else if (condop == LIR_ule)
|
||||||
|
JBE(targ);
|
||||||
|
else if (condop == LIR_ugt)
|
||||||
|
JA(targ);
|
||||||
|
else //if (condop == LIR_uge)
|
||||||
|
JAE(targ);
|
||||||
|
}
|
||||||
|
at = _nIns;
|
||||||
|
asm_cmp(cond);
|
||||||
|
return at;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_cmp(LIns *cond)
|
||||||
|
{
|
||||||
|
LOpcode condop = cond->opcode();
|
||||||
|
|
||||||
|
// LIR_ov and LIR_cs recycle the flags set by arithmetic ops
|
||||||
|
if ((condop == LIR_ov) || (condop == LIR_cs))
|
||||||
|
return;
|
||||||
|
|
||||||
|
LInsp lhs = cond->oprnd1();
|
||||||
|
LInsp rhs = cond->oprnd2();
|
||||||
|
Reservation *rA, *rB;
|
||||||
|
|
||||||
|
// Not supported yet.
|
||||||
|
NanoAssert(!lhs->isQuad() && !rhs->isQuad());
|
||||||
|
|
||||||
|
// ready to issue the compare
|
||||||
|
if (rhs->isconst())
|
||||||
|
{
|
||||||
|
int c = rhs->constval();
|
||||||
|
if (c == 0 && cond->isop(LIR_eq)) {
|
||||||
|
Register r = findRegFor(lhs, GpRegs);
|
||||||
|
TEST(r,r);
|
||||||
|
// No 64-bit immediates so fall-back to below
|
||||||
|
}
|
||||||
|
else if (!rhs->isQuad()) {
|
||||||
|
Register r = getBaseReg(lhs, c, GpRegs);
|
||||||
|
CMPi(r, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
findRegFor2(GpRegs, lhs, rA, rhs, rB);
|
||||||
|
Register ra = rA->reg;
|
||||||
|
Register rb = rB->reg;
|
||||||
|
CMP(ra, rb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_loop(LInsp ins, NInsList& loopJumps)
|
||||||
|
{
|
||||||
|
(void)ins;
|
||||||
|
JMP_long_placeholder(); // jump to SOT
|
||||||
|
verbose_only( if (_verbose && _outputCache) { _outputCache->removeLast(); outputf(" jmp SOT"); } );
|
||||||
|
|
||||||
|
loopJumps.add(_nIns);
|
||||||
|
|
||||||
|
#ifdef NJ_VERBOSE
|
||||||
|
// branching from this frag to ourself.
|
||||||
|
if (_frago->core()->config.show_stats)
|
||||||
|
LDi(argRegs[1], int((Fragment*)_thisfrag));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
assignSavedParams();
|
||||||
|
|
||||||
|
// restore first parameter, the only one we use
|
||||||
|
LInsp state = _thisfrag->lirbuf->state;
|
||||||
|
findSpecificRegFor(state, argRegs[state->imm8()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_fcond(LInsp ins)
|
||||||
|
{
|
||||||
|
// only want certain regs
|
||||||
|
Register r = prepResultReg(ins, AllowableFlagRegs);
|
||||||
|
asm_setcc(r, ins);
|
||||||
|
#ifdef NJ_ARM_VFP
|
||||||
|
SETE(r);
|
||||||
|
#else
|
||||||
|
// SETcc only sets low 8 bits, so extend
|
||||||
|
MOVZX8(r,r);
|
||||||
|
SETNP(r);
|
||||||
|
#endif
|
||||||
|
asm_fcmp(ins);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_cond(LInsp ins)
|
||||||
|
{
|
||||||
|
// only want certain regs
|
||||||
|
LOpcode op = ins->opcode();
|
||||||
|
Register r = prepResultReg(ins, AllowableFlagRegs);
|
||||||
|
// SETcc only sets low 8 bits, so extend
|
||||||
|
MOVZX8(r,r);
|
||||||
|
if (op == LIR_eq)
|
||||||
|
SETE(r);
|
||||||
|
else if (op == LIR_ov)
|
||||||
|
SETO(r);
|
||||||
|
else if (op == LIR_cs)
|
||||||
|
SETC(r);
|
||||||
|
else if (op == LIR_lt)
|
||||||
|
SETL(r);
|
||||||
|
else if (op == LIR_le)
|
||||||
|
SETLE(r);
|
||||||
|
else if (op == LIR_gt)
|
||||||
|
SETG(r);
|
||||||
|
else if (op == LIR_ge)
|
||||||
|
SETGE(r);
|
||||||
|
else if (op == LIR_ult)
|
||||||
|
SETB(r);
|
||||||
|
else if (op == LIR_ule)
|
||||||
|
SETBE(r);
|
||||||
|
else if (op == LIR_ugt)
|
||||||
|
SETA(r);
|
||||||
|
else // if (op == LIR_uge)
|
||||||
|
SETAE(r);
|
||||||
|
asm_cmp(ins);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_arith(LInsp ins)
|
||||||
|
{
|
||||||
|
LOpcode op = ins->opcode();
|
||||||
|
LInsp lhs = ins->oprnd1();
|
||||||
|
LInsp rhs = ins->oprnd2();
|
||||||
|
|
||||||
|
Register rb = UnknownReg;
|
||||||
|
RegisterMask allow = GpRegs;
|
||||||
|
bool forceReg = (op == LIR_mul || !rhs->isconst());
|
||||||
|
|
||||||
|
#ifdef NANOJIT_ARM
|
||||||
|
// Arm can't do an immediate op with immediates
|
||||||
|
// outside of +/-255 (for AND) r outside of
|
||||||
|
// 0..255 for others.
|
||||||
|
if (!forceReg)
|
||||||
|
{
|
||||||
|
if (rhs->isconst() && !isU8(rhs->constval()))
|
||||||
|
forceReg = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (lhs != rhs && forceReg)
|
||||||
|
{
|
||||||
|
if ((rb = asm_binop_rhs_reg(ins)) == UnknownReg) {
|
||||||
|
rb = findRegFor(rhs, allow);
|
||||||
|
}
|
||||||
|
allow &= ~rmask(rb);
|
||||||
|
}
|
||||||
|
else if ((op == LIR_add||op == LIR_addp) && lhs->isop(LIR_alloc) && rhs->isconst()) {
|
||||||
|
// add alloc+const, use lea
|
||||||
|
Register rr = prepResultReg(ins, allow);
|
||||||
|
int d = findMemFor(lhs) + rhs->constval();
|
||||||
|
LEA(rr, d, FP);
|
||||||
|
}
|
||||||
|
|
||||||
|
Register rr = prepResultReg(ins, allow);
|
||||||
|
Reservation* rA = getresv(lhs);
|
||||||
|
Register ra;
|
||||||
|
// if this is last use of lhs in reg, we can re-use result reg
|
||||||
|
if (rA == 0 || (ra = rA->reg) == UnknownReg)
|
||||||
|
ra = findSpecificRegFor(lhs, rr);
|
||||||
|
// else, rA already has a register assigned.
|
||||||
|
|
||||||
|
if (forceReg)
|
||||||
|
{
|
||||||
|
if (lhs == rhs)
|
||||||
|
rb = ra;
|
||||||
|
|
||||||
|
if (op == LIR_add || op == LIR_addp)
|
||||||
|
ADD(rr, rb);
|
||||||
|
else if (op == LIR_sub)
|
||||||
|
SUB(rr, rb);
|
||||||
|
else if (op == LIR_mul)
|
||||||
|
MUL(rr, rb);
|
||||||
|
else if (op == LIR_and)
|
||||||
|
AND(rr, rb);
|
||||||
|
else if (op == LIR_or)
|
||||||
|
OR(rr, rb);
|
||||||
|
else if (op == LIR_xor)
|
||||||
|
XOR(rr, rb);
|
||||||
|
else if (op == LIR_lsh)
|
||||||
|
SHL(rr, rb);
|
||||||
|
else if (op == LIR_rsh)
|
||||||
|
SAR(rr, rb);
|
||||||
|
else if (op == LIR_ush)
|
||||||
|
SHR(rr, rb);
|
||||||
|
else
|
||||||
|
NanoAssertMsg(0, "Unsupported");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int c = rhs->constval();
|
||||||
|
if (op == LIR_add || op == LIR_addp) {
|
||||||
|
{
|
||||||
|
ADDi(rr, c);
|
||||||
|
}
|
||||||
|
} else if (op == LIR_sub) {
|
||||||
|
{
|
||||||
|
SUBi(rr, c);
|
||||||
|
}
|
||||||
|
} else if (op == LIR_and)
|
||||||
|
ANDi(rr, c);
|
||||||
|
else if (op == LIR_or)
|
||||||
|
ORi(rr, c);
|
||||||
|
else if (op == LIR_xor)
|
||||||
|
XORi(rr, c);
|
||||||
|
else if (op == LIR_lsh)
|
||||||
|
SHLi(rr, c);
|
||||||
|
else if (op == LIR_rsh)
|
||||||
|
SARi(rr, c);
|
||||||
|
else if (op == LIR_ush)
|
||||||
|
SHRi(rr, c);
|
||||||
|
else
|
||||||
|
NanoAssertMsg(0, "Unsupported");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( rr != ra )
|
||||||
|
MR(rr,ra);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_neg_not(LInsp ins)
|
||||||
|
{
|
||||||
|
LOpcode op = ins->opcode();
|
||||||
|
Register rr = prepResultReg(ins, GpRegs);
|
||||||
|
|
||||||
|
LIns* lhs = ins->oprnd1();
|
||||||
|
Reservation *rA = getresv(lhs);
|
||||||
|
// if this is last use of lhs in reg, we can re-use result reg
|
||||||
|
Register ra;
|
||||||
|
if (rA == 0 || (ra=rA->reg) == UnknownReg)
|
||||||
|
ra = findSpecificRegFor(lhs, rr);
|
||||||
|
// else, rA already has a register assigned.
|
||||||
|
|
||||||
|
if (op == LIR_not)
|
||||||
|
NOT(rr);
|
||||||
|
else
|
||||||
|
NEG(rr);
|
||||||
|
|
||||||
|
if ( rr != ra )
|
||||||
|
MR(rr,ra);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_ld(LInsp ins)
|
||||||
|
{
|
||||||
|
LOpcode op = ins->opcode();
|
||||||
|
LIns* base = ins->oprnd1();
|
||||||
|
LIns* disp = ins->oprnd2();
|
||||||
|
Register rr = prepResultReg(ins, GpRegs);
|
||||||
|
int d = disp->constval();
|
||||||
|
Register ra = getBaseReg(base, d, GpRegs);
|
||||||
|
if (op == LIR_ldcb)
|
||||||
|
LD8Z(rr, d, ra);
|
||||||
|
else
|
||||||
|
LD(rr, d, ra);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_cmov(LInsp ins)
|
||||||
|
{
|
||||||
|
LOpcode op = ins->opcode();
|
||||||
|
LIns* condval = ins->oprnd1();
|
||||||
|
NanoAssert(condval->isCmp());
|
||||||
|
|
||||||
|
LIns* values = ins->oprnd2();
|
||||||
|
|
||||||
|
NanoAssert(values->opcode() == LIR_2);
|
||||||
|
LIns* iftrue = values->oprnd1();
|
||||||
|
LIns* iffalse = values->oprnd2();
|
||||||
|
|
||||||
|
NanoAssert(op == LIR_qcmov || (!iftrue->isQuad() && !iffalse->isQuad()));
|
||||||
|
|
||||||
|
const Register rr = prepResultReg(ins, GpRegs);
|
||||||
|
|
||||||
|
// this code assumes that neither LD nor MR nor MRcc set any of the condition flags.
|
||||||
|
// (This is true on Intel, is it true on all architectures?)
|
||||||
|
const Register iffalsereg = findRegFor(iffalse, GpRegs & ~rmask(rr));
|
||||||
|
if (op == LIR_cmov) {
|
||||||
|
switch (condval->opcode())
|
||||||
|
{
|
||||||
|
// note that these are all opposites...
|
||||||
|
case LIR_eq: MRNE(rr, iffalsereg); break;
|
||||||
|
case LIR_ov: MRNO(rr, iffalsereg); break;
|
||||||
|
case LIR_cs: MRNC(rr, iffalsereg); break;
|
||||||
|
case LIR_lt: MRGE(rr, iffalsereg); break;
|
||||||
|
case LIR_le: MRG(rr, iffalsereg); break;
|
||||||
|
case LIR_gt: MRLE(rr, iffalsereg); break;
|
||||||
|
case LIR_ge: MRL(rr, iffalsereg); break;
|
||||||
|
case LIR_ult: MRAE(rr, iffalsereg); break;
|
||||||
|
case LIR_ule: MRA(rr, iffalsereg); break;
|
||||||
|
case LIR_ugt: MRBE(rr, iffalsereg); break;
|
||||||
|
case LIR_uge: MRB(rr, iffalsereg); break;
|
||||||
|
debug_only( default: NanoAssert(0); break; )
|
||||||
|
}
|
||||||
|
} else if (op == LIR_qcmov) {
|
||||||
|
NanoAssert(0);
|
||||||
|
}
|
||||||
|
/*const Register iftruereg =*/ findSpecificRegFor(iftrue, rr);
|
||||||
|
asm_cmp(condval);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_qhi(LInsp ins)
|
||||||
|
{
|
||||||
|
Register rr = prepResultReg(ins, GpRegs);
|
||||||
|
LIns *q = ins->oprnd1();
|
||||||
|
int d = findMemFor(q);
|
||||||
|
LD(rr, d+4, FP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_param(LInsp ins)
|
||||||
|
{
|
||||||
|
uint32_t a = ins->imm8();
|
||||||
|
uint32_t kind = ins->imm8b();
|
||||||
|
if (kind == 0) {
|
||||||
|
// ordinary param
|
||||||
|
AbiKind abi = _thisfrag->lirbuf->abi;
|
||||||
|
uint32_t abi_regcount = abi == ABI_FASTCALL ? 2 : abi == ABI_THISCALL ? 1 : 0;
|
||||||
|
if (a < abi_regcount) {
|
||||||
|
// incoming arg in register
|
||||||
|
prepResultReg(ins, rmask(argRegs[a]));
|
||||||
|
} else {
|
||||||
|
// incoming arg is on stack, and EBP points nearby (see genPrologue)
|
||||||
|
Register r = prepResultReg(ins, GpRegs);
|
||||||
|
int d = (a - abi_regcount) * sizeof(intptr_t) + 8;
|
||||||
|
LD(r, d, FP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// saved param
|
||||||
|
prepResultReg(ins, rmask(savedRegs[a]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_short(LInsp ins)
|
||||||
|
{
|
||||||
|
Register rr = prepResultReg(ins, GpRegs);
|
||||||
|
int32_t val = ins->imm16();
|
||||||
|
if (val == 0)
|
||||||
|
XOR(rr,rr);
|
||||||
|
else
|
||||||
|
LDi(rr, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_int(LInsp ins)
|
||||||
|
{
|
||||||
|
Register rr = prepResultReg(ins, GpRegs);
|
||||||
|
int32_t val = ins->imm32();
|
||||||
|
if (val == 0)
|
||||||
|
XOR(rr,rr);
|
||||||
|
else
|
||||||
|
LDi(rr, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_quad(LInsp ins)
|
||||||
|
{
|
||||||
|
Reservation *rR = getresv(ins);
|
||||||
|
Register rr = rR->reg;
|
||||||
|
if (rr != UnknownReg)
|
||||||
|
{
|
||||||
|
// @todo -- add special-cases for 0 and 1
|
||||||
|
_allocator.retire(rr);
|
||||||
|
rR->reg = UnknownReg;
|
||||||
|
NanoAssert((rmask(rr) & FpRegs) != 0);
|
||||||
|
|
||||||
|
const double d = ins->constvalf();
|
||||||
|
const uint64_t q = ins->constvalq();
|
||||||
|
if (rmask(rr) & XmmRegs) {
|
||||||
|
if (q == 0.0) {
|
||||||
|
// test (int64)0 since -0.0 == 0.0
|
||||||
|
SSE_XORPDr(rr, rr);
|
||||||
|
} else if (d == 1.0) {
|
||||||
|
// 1.0 is extremely frequent and worth special-casing!
|
||||||
|
static const double k_ONE = 1.0;
|
||||||
|
LDSDm(rr, &k_ONE);
|
||||||
|
} else {
|
||||||
|
findMemFor(ins);
|
||||||
|
const int d = disp(rR);
|
||||||
|
SSE_LDQ(rr, d, FP);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (q == 0.0) {
|
||||||
|
// test (int64)0 since -0.0 == 0.0
|
||||||
|
FLDZ();
|
||||||
|
} else if (d == 1.0) {
|
||||||
|
FLD1();
|
||||||
|
} else {
|
||||||
|
findMemFor(ins);
|
||||||
|
int d = disp(rR);
|
||||||
|
FLDQ(d,FP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @todo, if we used xor, ldsd, fldz, etc above, we don't need mem here
|
||||||
|
int d = disp(rR);
|
||||||
|
freeRsrcOf(ins, false);
|
||||||
|
if (d)
|
||||||
|
{
|
||||||
|
const int32_t* p = (const int32_t*) (ins-2);
|
||||||
|
STi(FP,d+4,p[1]);
|
||||||
|
STi(FP,d,p[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_qlo(LInsp ins)
|
||||||
|
{
|
||||||
|
LIns *q = ins->oprnd1();
|
||||||
|
|
||||||
|
Reservation *resv = getresv(ins);
|
||||||
|
Register rr = resv->reg;
|
||||||
|
if (rr == UnknownReg) {
|
||||||
|
// store quad in spill loc
|
||||||
|
int d = disp(resv);
|
||||||
|
freeRsrcOf(ins, false);
|
||||||
|
Register qr = findRegFor(q, XmmRegs);
|
||||||
|
SSE_MOVDm(d, FP, qr);
|
||||||
|
} else {
|
||||||
|
freeRsrcOf(ins, false);
|
||||||
|
Register qr = findRegFor(q, XmmRegs);
|
||||||
|
SSE_MOVD(rr,qr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Assembler::asm_arg(ArgSize sz, LInsp p, Register r)
|
void Assembler::asm_arg(ArgSize sz, LInsp p, Register r)
|
||||||
{
|
{
|
||||||
if (sz == ARGSIZE_Q)
|
if (sz == ARGSIZE_Q)
|
||||||
@ -646,13 +1120,6 @@ Assembler::asm_quad(LInsp ins)
|
|||||||
//asm_output("<<< asm_quad");
|
//asm_output("<<< asm_quad");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
Assembler::asm_qlo(LInsp ins, LInsp q)
|
|
||||||
{
|
|
||||||
(void)ins; (void)q;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Assembler::asm_nongp_copy(Register r, Register s)
|
Assembler::asm_nongp_copy(Register r, Register s)
|
||||||
{
|
{
|
||||||
|
@ -350,6 +350,7 @@ namespace nanojit
|
|||||||
asm_mmq(rb, dr, FP, da);
|
asm_mmq(rb, dr, FP, da);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Assembler::asm_quad(LInsp ins)
|
void Assembler::asm_quad(LInsp ins)
|
||||||
{
|
{
|
||||||
Reservation *rR = getresv(ins);
|
Reservation *rR = getresv(ins);
|
||||||
@ -363,10 +364,477 @@ namespace nanojit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Assembler::asm_qlo(LInsp ins, LInsp q)
|
NIns* Assembler::asm_branch(bool branchOnFalse, LInsp cond, NIns* targ)
|
||||||
{
|
{
|
||||||
(void)ins; (void)q;
|
NIns* at = 0;
|
||||||
return false;
|
LOpcode condop = cond->opcode();
|
||||||
|
NanoAssert(cond->isCond());
|
||||||
|
#ifndef NJ_SOFTFLOAT
|
||||||
|
if (condop >= LIR_feq && condop <= LIR_fge)
|
||||||
|
{
|
||||||
|
return asm_jmpcc(branchOnFalse, cond, targ);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// produce the branch
|
||||||
|
if (branchOnFalse)
|
||||||
|
{
|
||||||
|
if (condop == LIR_eq)
|
||||||
|
JNE(targ);
|
||||||
|
else if (condop == LIR_ov)
|
||||||
|
JNO(targ);
|
||||||
|
else if (condop == LIR_cs)
|
||||||
|
JNC(targ);
|
||||||
|
else if (condop == LIR_lt)
|
||||||
|
JNL(targ);
|
||||||
|
else if (condop == LIR_le)
|
||||||
|
JNLE(targ);
|
||||||
|
else if (condop == LIR_gt)
|
||||||
|
JNG(targ);
|
||||||
|
else if (condop == LIR_ge)
|
||||||
|
JNGE(targ);
|
||||||
|
else if (condop == LIR_ult)
|
||||||
|
JNB(targ);
|
||||||
|
else if (condop == LIR_ule)
|
||||||
|
JNBE(targ);
|
||||||
|
else if (condop == LIR_ugt)
|
||||||
|
JNA(targ);
|
||||||
|
else //if (condop == LIR_uge)
|
||||||
|
JNAE(targ);
|
||||||
|
}
|
||||||
|
else // op == LIR_xt
|
||||||
|
{
|
||||||
|
if (condop == LIR_eq)
|
||||||
|
JE(targ);
|
||||||
|
else if (condop == LIR_ov)
|
||||||
|
JO(targ);
|
||||||
|
else if (condop == LIR_cs)
|
||||||
|
JC(targ);
|
||||||
|
else if (condop == LIR_lt)
|
||||||
|
JL(targ);
|
||||||
|
else if (condop == LIR_le)
|
||||||
|
JLE(targ);
|
||||||
|
else if (condop == LIR_gt)
|
||||||
|
JG(targ);
|
||||||
|
else if (condop == LIR_ge)
|
||||||
|
JGE(targ);
|
||||||
|
else if (condop == LIR_ult)
|
||||||
|
JB(targ);
|
||||||
|
else if (condop == LIR_ule)
|
||||||
|
JBE(targ);
|
||||||
|
else if (condop == LIR_ugt)
|
||||||
|
JA(targ);
|
||||||
|
else //if (condop == LIR_uge)
|
||||||
|
JAE(targ);
|
||||||
|
}
|
||||||
|
at = _nIns;
|
||||||
|
asm_cmp(cond);
|
||||||
|
return at;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_cmp(LIns *cond)
|
||||||
|
{
|
||||||
|
LOpcode condop = cond->opcode();
|
||||||
|
|
||||||
|
// LIR_ov and LIR_cs recycle the flags set by arithmetic ops
|
||||||
|
if ((condop == LIR_ov) || (condop == LIR_cs))
|
||||||
|
return;
|
||||||
|
|
||||||
|
LInsp lhs = cond->oprnd1();
|
||||||
|
LInsp rhs = cond->oprnd2();
|
||||||
|
Reservation *rA, *rB;
|
||||||
|
|
||||||
|
// Not supported yet.
|
||||||
|
NanoAssert(!lhs->isQuad() && !rhs->isQuad());
|
||||||
|
|
||||||
|
// ready to issue the compare
|
||||||
|
if (rhs->isconst())
|
||||||
|
{
|
||||||
|
int c = rhs->constval();
|
||||||
|
if (c == 0 && cond->isop(LIR_eq)) {
|
||||||
|
Register r = findRegFor(lhs, GpRegs);
|
||||||
|
TEST(r,r);
|
||||||
|
// No 64-bit immediates so fall-back to below
|
||||||
|
}
|
||||||
|
else if (!rhs->isQuad()) {
|
||||||
|
Register r = getBaseReg(lhs, c, GpRegs);
|
||||||
|
CMPi(r, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
findRegFor2(GpRegs, lhs, rA, rhs, rB);
|
||||||
|
Register ra = rA->reg;
|
||||||
|
Register rb = rB->reg;
|
||||||
|
CMP(ra, rb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_loop(LInsp ins, NInsList& loopJumps)
|
||||||
|
{
|
||||||
|
(void)ins;
|
||||||
|
JMP_long_placeholder(); // jump to SOT
|
||||||
|
verbose_only( if (_verbose && _outputCache) { _outputCache->removeLast(); outputf(" jmp SOT"); } );
|
||||||
|
|
||||||
|
loopJumps.add(_nIns);
|
||||||
|
|
||||||
|
#ifdef NJ_VERBOSE
|
||||||
|
// branching from this frag to ourself.
|
||||||
|
if (_frago->core()->config.show_stats)
|
||||||
|
LDi(argRegs[1], int((Fragment*)_thisfrag));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
assignSavedParams();
|
||||||
|
|
||||||
|
// restore first parameter, the only one we use
|
||||||
|
LInsp state = _thisfrag->lirbuf->state;
|
||||||
|
findSpecificRegFor(state, argRegs[state->imm8()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_fcond(LInsp ins)
|
||||||
|
{
|
||||||
|
// only want certain regs
|
||||||
|
Register r = prepResultReg(ins, AllowableFlagRegs);
|
||||||
|
asm_setcc(r, ins);
|
||||||
|
#ifdef NJ_ARM_VFP
|
||||||
|
SETE(r);
|
||||||
|
#else
|
||||||
|
// SETcc only sets low 8 bits, so extend
|
||||||
|
MOVZX8(r,r);
|
||||||
|
SETNP(r);
|
||||||
|
#endif
|
||||||
|
asm_fcmp(ins);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_cond(LInsp ins)
|
||||||
|
{
|
||||||
|
// only want certain regs
|
||||||
|
LOpcode op = ins->opcode();
|
||||||
|
Register r = prepResultReg(ins, AllowableFlagRegs);
|
||||||
|
// SETcc only sets low 8 bits, so extend
|
||||||
|
MOVZX8(r,r);
|
||||||
|
if (op == LIR_eq)
|
||||||
|
SETE(r);
|
||||||
|
else if (op == LIR_ov)
|
||||||
|
SETO(r);
|
||||||
|
else if (op == LIR_cs)
|
||||||
|
SETC(r);
|
||||||
|
else if (op == LIR_lt)
|
||||||
|
SETL(r);
|
||||||
|
else if (op == LIR_le)
|
||||||
|
SETLE(r);
|
||||||
|
else if (op == LIR_gt)
|
||||||
|
SETG(r);
|
||||||
|
else if (op == LIR_ge)
|
||||||
|
SETGE(r);
|
||||||
|
else if (op == LIR_ult)
|
||||||
|
SETB(r);
|
||||||
|
else if (op == LIR_ule)
|
||||||
|
SETBE(r);
|
||||||
|
else if (op == LIR_ugt)
|
||||||
|
SETA(r);
|
||||||
|
else // if (op == LIR_uge)
|
||||||
|
SETAE(r);
|
||||||
|
asm_cmp(ins);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_arith(LInsp ins)
|
||||||
|
{
|
||||||
|
LOpcode op = ins->opcode();
|
||||||
|
LInsp lhs = ins->oprnd1();
|
||||||
|
LInsp rhs = ins->oprnd2();
|
||||||
|
|
||||||
|
Register rb = UnknownReg;
|
||||||
|
RegisterMask allow = GpRegs;
|
||||||
|
bool forceReg = (op == LIR_mul || !rhs->isconst());
|
||||||
|
|
||||||
|
#ifdef NANOJIT_ARM
|
||||||
|
// Arm can't do an immediate op with immediates
|
||||||
|
// outside of +/-255 (for AND) r outside of
|
||||||
|
// 0..255 for others.
|
||||||
|
if (!forceReg)
|
||||||
|
{
|
||||||
|
if (rhs->isconst() && !isU8(rhs->constval()))
|
||||||
|
forceReg = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (lhs != rhs && forceReg)
|
||||||
|
{
|
||||||
|
if ((rb = asm_binop_rhs_reg(ins)) == UnknownReg) {
|
||||||
|
rb = findRegFor(rhs, allow);
|
||||||
|
}
|
||||||
|
allow &= ~rmask(rb);
|
||||||
|
}
|
||||||
|
else if ((op == LIR_add||op == LIR_addp) && lhs->isop(LIR_alloc) && rhs->isconst()) {
|
||||||
|
// add alloc+const, use lea
|
||||||
|
Register rr = prepResultReg(ins, allow);
|
||||||
|
int d = findMemFor(lhs) + rhs->constval();
|
||||||
|
LEA(rr, d, FP);
|
||||||
|
}
|
||||||
|
|
||||||
|
Register rr = prepResultReg(ins, allow);
|
||||||
|
Reservation* rA = getresv(lhs);
|
||||||
|
Register ra;
|
||||||
|
// if this is last use of lhs in reg, we can re-use result reg
|
||||||
|
if (rA == 0 || (ra = rA->reg) == UnknownReg)
|
||||||
|
ra = findSpecificRegFor(lhs, rr);
|
||||||
|
// else, rA already has a register assigned.
|
||||||
|
|
||||||
|
if (forceReg)
|
||||||
|
{
|
||||||
|
if (lhs == rhs)
|
||||||
|
rb = ra;
|
||||||
|
|
||||||
|
if (op == LIR_add || op == LIR_addp)
|
||||||
|
ADD(rr, rb);
|
||||||
|
else if (op == LIR_sub)
|
||||||
|
SUB(rr, rb);
|
||||||
|
else if (op == LIR_mul)
|
||||||
|
MUL(rr, rb);
|
||||||
|
else if (op == LIR_and)
|
||||||
|
AND(rr, rb);
|
||||||
|
else if (op == LIR_or)
|
||||||
|
OR(rr, rb);
|
||||||
|
else if (op == LIR_xor)
|
||||||
|
XOR(rr, rb);
|
||||||
|
else if (op == LIR_lsh)
|
||||||
|
SHL(rr, rb);
|
||||||
|
else if (op == LIR_rsh)
|
||||||
|
SAR(rr, rb);
|
||||||
|
else if (op == LIR_ush)
|
||||||
|
SHR(rr, rb);
|
||||||
|
else
|
||||||
|
NanoAssertMsg(0, "Unsupported");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int c = rhs->constval();
|
||||||
|
if (op == LIR_add || op == LIR_addp) {
|
||||||
|
{
|
||||||
|
ADDi(rr, c);
|
||||||
|
}
|
||||||
|
} else if (op == LIR_sub) {
|
||||||
|
{
|
||||||
|
SUBi(rr, c);
|
||||||
|
}
|
||||||
|
} else if (op == LIR_and)
|
||||||
|
ANDi(rr, c);
|
||||||
|
else if (op == LIR_or)
|
||||||
|
ORi(rr, c);
|
||||||
|
else if (op == LIR_xor)
|
||||||
|
XORi(rr, c);
|
||||||
|
else if (op == LIR_lsh)
|
||||||
|
SHLi(rr, c);
|
||||||
|
else if (op == LIR_rsh)
|
||||||
|
SARi(rr, c);
|
||||||
|
else if (op == LIR_ush)
|
||||||
|
SHRi(rr, c);
|
||||||
|
else
|
||||||
|
NanoAssertMsg(0, "Unsupported");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( rr != ra )
|
||||||
|
MR(rr,ra);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_neg_not(LInsp ins)
|
||||||
|
{
|
||||||
|
LOpcode op = ins->opcode();
|
||||||
|
Register rr = prepResultReg(ins, GpRegs);
|
||||||
|
|
||||||
|
LIns* lhs = ins->oprnd1();
|
||||||
|
Reservation *rA = getresv(lhs);
|
||||||
|
// if this is last use of lhs in reg, we can re-use result reg
|
||||||
|
Register ra;
|
||||||
|
if (rA == 0 || (ra=rA->reg) == UnknownReg)
|
||||||
|
ra = findSpecificRegFor(lhs, rr);
|
||||||
|
// else, rA already has a register assigned.
|
||||||
|
|
||||||
|
if (op == LIR_not)
|
||||||
|
NOT(rr);
|
||||||
|
else
|
||||||
|
NEG(rr);
|
||||||
|
|
||||||
|
if ( rr != ra )
|
||||||
|
MR(rr,ra);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_ld(LInsp ins)
|
||||||
|
{
|
||||||
|
LOpcode op = ins->opcode();
|
||||||
|
LIns* base = ins->oprnd1();
|
||||||
|
LIns* disp = ins->oprnd2();
|
||||||
|
Register rr = prepResultReg(ins, GpRegs);
|
||||||
|
int d = disp->constval();
|
||||||
|
Register ra = getBaseReg(base, d, GpRegs);
|
||||||
|
if (op == LIR_ldcb)
|
||||||
|
LD8Z(rr, d, ra);
|
||||||
|
else
|
||||||
|
LD(rr, d, ra);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_cmov(LInsp ins)
|
||||||
|
{
|
||||||
|
LOpcode op = ins->opcode();
|
||||||
|
LIns* condval = ins->oprnd1();
|
||||||
|
NanoAssert(condval->isCmp());
|
||||||
|
|
||||||
|
LIns* values = ins->oprnd2();
|
||||||
|
|
||||||
|
NanoAssert(values->opcode() == LIR_2);
|
||||||
|
LIns* iftrue = values->oprnd1();
|
||||||
|
LIns* iffalse = values->oprnd2();
|
||||||
|
|
||||||
|
NanoAssert(op == LIR_qcmov || (!iftrue->isQuad() && !iffalse->isQuad()));
|
||||||
|
|
||||||
|
const Register rr = prepResultReg(ins, GpRegs);
|
||||||
|
|
||||||
|
// this code assumes that neither LD nor MR nor MRcc set any of the condition flags.
|
||||||
|
// (This is true on Intel, is it true on all architectures?)
|
||||||
|
const Register iffalsereg = findRegFor(iffalse, GpRegs & ~rmask(rr));
|
||||||
|
if (op == LIR_cmov) {
|
||||||
|
switch (condval->opcode())
|
||||||
|
{
|
||||||
|
// note that these are all opposites...
|
||||||
|
case LIR_eq: MRNE(rr, iffalsereg); break;
|
||||||
|
case LIR_ov: MRNO(rr, iffalsereg); break;
|
||||||
|
case LIR_cs: MRNC(rr, iffalsereg); break;
|
||||||
|
case LIR_lt: MRGE(rr, iffalsereg); break;
|
||||||
|
case LIR_le: MRG(rr, iffalsereg); break;
|
||||||
|
case LIR_gt: MRLE(rr, iffalsereg); break;
|
||||||
|
case LIR_ge: MRL(rr, iffalsereg); break;
|
||||||
|
case LIR_ult: MRAE(rr, iffalsereg); break;
|
||||||
|
case LIR_ule: MRA(rr, iffalsereg); break;
|
||||||
|
case LIR_ugt: MRBE(rr, iffalsereg); break;
|
||||||
|
case LIR_uge: MRB(rr, iffalsereg); break;
|
||||||
|
debug_only( default: NanoAssert(0); break; )
|
||||||
|
}
|
||||||
|
} else if (op == LIR_qcmov) {
|
||||||
|
NanoAssert(0);
|
||||||
|
}
|
||||||
|
/*const Register iftruereg =*/ findSpecificRegFor(iftrue, rr);
|
||||||
|
asm_cmp(condval);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_qhi(LInsp ins)
|
||||||
|
{
|
||||||
|
Register rr = prepResultReg(ins, GpRegs);
|
||||||
|
LIns *q = ins->oprnd1();
|
||||||
|
int d = findMemFor(q);
|
||||||
|
LD(rr, d+4, FP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_param(LInsp ins)
|
||||||
|
{
|
||||||
|
uint32_t a = ins->imm8();
|
||||||
|
uint32_t kind = ins->imm8b();
|
||||||
|
if (kind == 0) {
|
||||||
|
// ordinary param
|
||||||
|
AbiKind abi = _thisfrag->lirbuf->abi;
|
||||||
|
uint32_t abi_regcount = abi == ABI_FASTCALL ? 2 : abi == ABI_THISCALL ? 1 : 0;
|
||||||
|
if (a < abi_regcount) {
|
||||||
|
// incoming arg in register
|
||||||
|
prepResultReg(ins, rmask(argRegs[a]));
|
||||||
|
} else {
|
||||||
|
// incoming arg is on stack, and EBP points nearby (see genPrologue)
|
||||||
|
Register r = prepResultReg(ins, GpRegs);
|
||||||
|
int d = (a - abi_regcount) * sizeof(intptr_t) + 8;
|
||||||
|
LD(r, d, FP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// saved param
|
||||||
|
prepResultReg(ins, rmask(savedRegs[a]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_short(LInsp ins)
|
||||||
|
{
|
||||||
|
Register rr = prepResultReg(ins, GpRegs);
|
||||||
|
int32_t val = ins->imm16();
|
||||||
|
if (val == 0)
|
||||||
|
XOR(rr,rr);
|
||||||
|
else
|
||||||
|
LDi(rr, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_int(LInsp ins)
|
||||||
|
{
|
||||||
|
Register rr = prepResultReg(ins, GpRegs);
|
||||||
|
int32_t val = ins->imm32();
|
||||||
|
if (val == 0)
|
||||||
|
XOR(rr,rr);
|
||||||
|
else
|
||||||
|
LDi(rr, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_quad(LInsp ins)
|
||||||
|
{
|
||||||
|
Reservation *rR = getresv(ins);
|
||||||
|
Register rr = rR->reg;
|
||||||
|
if (rr != UnknownReg)
|
||||||
|
{
|
||||||
|
// @todo -- add special-cases for 0 and 1
|
||||||
|
_allocator.retire(rr);
|
||||||
|
rR->reg = UnknownReg;
|
||||||
|
NanoAssert((rmask(rr) & FpRegs) != 0);
|
||||||
|
|
||||||
|
const double d = ins->constvalf();
|
||||||
|
const uint64_t q = ins->constvalq();
|
||||||
|
if (rmask(rr) & XmmRegs) {
|
||||||
|
if (q == 0.0) {
|
||||||
|
// test (int64)0 since -0.0 == 0.0
|
||||||
|
SSE_XORPDr(rr, rr);
|
||||||
|
} else if (d == 1.0) {
|
||||||
|
// 1.0 is extremely frequent and worth special-casing!
|
||||||
|
static const double k_ONE = 1.0;
|
||||||
|
LDSDm(rr, &k_ONE);
|
||||||
|
} else {
|
||||||
|
findMemFor(ins);
|
||||||
|
const int d = disp(rR);
|
||||||
|
SSE_LDQ(rr, d, FP);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (q == 0.0) {
|
||||||
|
// test (int64)0 since -0.0 == 0.0
|
||||||
|
FLDZ();
|
||||||
|
} else if (d == 1.0) {
|
||||||
|
FLD1();
|
||||||
|
} else {
|
||||||
|
findMemFor(ins);
|
||||||
|
int d = disp(rR);
|
||||||
|
FLDQ(d,FP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @todo, if we used xor, ldsd, fldz, etc above, we don't need mem here
|
||||||
|
int d = disp(rR);
|
||||||
|
freeRsrcOf(ins, false);
|
||||||
|
if (d)
|
||||||
|
{
|
||||||
|
const int32_t* p = (const int32_t*) (ins-2);
|
||||||
|
STi(FP,d+4,p[1]);
|
||||||
|
STi(FP,d,p[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_qlo(LInsp ins)
|
||||||
|
{
|
||||||
|
LIns *q = ins->oprnd1();
|
||||||
|
Reservation *resv = getresv(ins);
|
||||||
|
Register rr = resv->reg;
|
||||||
|
if (rr == UnknownReg) {
|
||||||
|
// store quad in spill loc
|
||||||
|
int d = disp(resv);
|
||||||
|
freeRsrcOf(ins, false);
|
||||||
|
Register qr = findRegFor(q, XmmRegs);
|
||||||
|
SSE_MOVDm(d, FP, qr);
|
||||||
|
} else {
|
||||||
|
freeRsrcOf(ins, false);
|
||||||
|
Register qr = findRegFor(q, XmmRegs);
|
||||||
|
SSE_MOVD(rr,qr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Assembler::asm_nongp_copy(Register r, Register s)
|
void Assembler::asm_nongp_copy(Register r, Register s)
|
||||||
|
@ -825,6 +825,462 @@ namespace nanojit
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NIns* Assembler::asm_branch(bool branchOnFalse, LInsp cond, NIns* targ)
|
||||||
|
{
|
||||||
|
NIns* at = 0;
|
||||||
|
LOpcode condop = cond->opcode();
|
||||||
|
NanoAssert(cond->isCond());
|
||||||
|
#ifndef NJ_SOFTFLOAT
|
||||||
|
if (condop >= LIR_feq && condop <= LIR_fge)
|
||||||
|
{
|
||||||
|
return asm_jmpcc(branchOnFalse, cond, targ);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// produce the branch
|
||||||
|
if (branchOnFalse)
|
||||||
|
{
|
||||||
|
if (condop == LIR_eq)
|
||||||
|
JNE(targ);
|
||||||
|
else if (condop == LIR_ov)
|
||||||
|
JNO(targ);
|
||||||
|
else if (condop == LIR_cs)
|
||||||
|
JNC(targ);
|
||||||
|
else if (condop == LIR_lt)
|
||||||
|
JNL(targ);
|
||||||
|
else if (condop == LIR_le)
|
||||||
|
JNLE(targ);
|
||||||
|
else if (condop == LIR_gt)
|
||||||
|
JNG(targ);
|
||||||
|
else if (condop == LIR_ge)
|
||||||
|
JNGE(targ);
|
||||||
|
else if (condop == LIR_ult)
|
||||||
|
JNB(targ);
|
||||||
|
else if (condop == LIR_ule)
|
||||||
|
JNBE(targ);
|
||||||
|
else if (condop == LIR_ugt)
|
||||||
|
JNA(targ);
|
||||||
|
else //if (condop == LIR_uge)
|
||||||
|
JNAE(targ);
|
||||||
|
}
|
||||||
|
else // op == LIR_xt
|
||||||
|
{
|
||||||
|
if (condop == LIR_eq)
|
||||||
|
JE(targ);
|
||||||
|
else if (condop == LIR_ov)
|
||||||
|
JO(targ);
|
||||||
|
else if (condop == LIR_cs)
|
||||||
|
JC(targ);
|
||||||
|
else if (condop == LIR_lt)
|
||||||
|
JL(targ);
|
||||||
|
else if (condop == LIR_le)
|
||||||
|
JLE(targ);
|
||||||
|
else if (condop == LIR_gt)
|
||||||
|
JG(targ);
|
||||||
|
else if (condop == LIR_ge)
|
||||||
|
JGE(targ);
|
||||||
|
else if (condop == LIR_ult)
|
||||||
|
JB(targ);
|
||||||
|
else if (condop == LIR_ule)
|
||||||
|
JBE(targ);
|
||||||
|
else if (condop == LIR_ugt)
|
||||||
|
JA(targ);
|
||||||
|
else //if (condop == LIR_uge)
|
||||||
|
JAE(targ);
|
||||||
|
}
|
||||||
|
at = _nIns;
|
||||||
|
asm_cmp(cond);
|
||||||
|
return at;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_cmp(LIns *cond)
|
||||||
|
{
|
||||||
|
LOpcode condop = cond->opcode();
|
||||||
|
|
||||||
|
// LIR_ov and LIR_cs recycle the flags set by arithmetic ops
|
||||||
|
if ((condop == LIR_ov) || (condop == LIR_cs))
|
||||||
|
return;
|
||||||
|
|
||||||
|
LInsp lhs = cond->oprnd1();
|
||||||
|
LInsp rhs = cond->oprnd2();
|
||||||
|
Reservation *rA, *rB;
|
||||||
|
|
||||||
|
NanoAssert((!lhs->isQuad() && !rhs->isQuad()) || (lhs->isQuad() && rhs->isQuad()));
|
||||||
|
|
||||||
|
// Not supported yet.
|
||||||
|
#if !defined NANOJIT_64BIT
|
||||||
|
NanoAssert(!lhs->isQuad() && !rhs->isQuad());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ready to issue the compare
|
||||||
|
if (rhs->isconst())
|
||||||
|
{
|
||||||
|
int c = rhs->constval();
|
||||||
|
if (c == 0 && cond->isop(LIR_eq)) {
|
||||||
|
Register r = findRegFor(lhs, GpRegs);
|
||||||
|
if (rhs->isQuad()) {
|
||||||
|
#if defined NANOJIT_64BIT
|
||||||
|
TESTQ(r, r);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
TEST(r,r);
|
||||||
|
}
|
||||||
|
// No 64-bit immediates so fall-back to below
|
||||||
|
}
|
||||||
|
else if (!rhs->isQuad()) {
|
||||||
|
Register r = getBaseReg(lhs, c, GpRegs);
|
||||||
|
CMPi(r, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
findRegFor2(GpRegs, lhs, rA, rhs, rB);
|
||||||
|
Register ra = rA->reg;
|
||||||
|
Register rb = rB->reg;
|
||||||
|
if (rhs->isQuad()) {
|
||||||
|
#if defined NANOJIT_64BIT
|
||||||
|
CMPQ(ra, rb);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
CMP(ra, rb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_loop(LInsp ins, NInsList& loopJumps)
|
||||||
|
{
|
||||||
|
(void)ins;
|
||||||
|
JMP_long_placeholder(); // jump to SOT
|
||||||
|
verbose_only( if (_verbose && _outputCache) { _outputCache->removeLast(); outputf(" jmp SOT"); } );
|
||||||
|
|
||||||
|
loopJumps.add(_nIns);
|
||||||
|
|
||||||
|
#ifdef NJ_VERBOSE
|
||||||
|
// branching from this frag to ourself.
|
||||||
|
if (_frago->core()->config.show_stats)
|
||||||
|
#if defined NANOJIT_AMD64
|
||||||
|
LDQi(argRegs[1], intptr_t((Fragment*)_thisfrag));
|
||||||
|
#else
|
||||||
|
LDi(argRegs[1], int((Fragment*)_thisfrag));
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
assignSavedParams();
|
||||||
|
|
||||||
|
// restore first parameter, the only one we use
|
||||||
|
LInsp state = _thisfrag->lirbuf->state;
|
||||||
|
findSpecificRegFor(state, argRegs[state->imm8()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_fcond(LInsp ins)
|
||||||
|
{
|
||||||
|
// only want certain regs
|
||||||
|
Register r = prepResultReg(ins, AllowableFlagRegs);
|
||||||
|
asm_setcc(r, ins);
|
||||||
|
#ifdef NJ_ARM_VFP
|
||||||
|
SETE(r);
|
||||||
|
#else
|
||||||
|
// SETcc only sets low 8 bits, so extend
|
||||||
|
MOVZX8(r,r);
|
||||||
|
SETNP(r);
|
||||||
|
#endif
|
||||||
|
asm_fcmp(ins);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_cond(LInsp ins)
|
||||||
|
{
|
||||||
|
// only want certain regs
|
||||||
|
LOpcode op = ins->opcode();
|
||||||
|
Register r = prepResultReg(ins, AllowableFlagRegs);
|
||||||
|
// SETcc only sets low 8 bits, so extend
|
||||||
|
MOVZX8(r,r);
|
||||||
|
if (op == LIR_eq)
|
||||||
|
SETE(r);
|
||||||
|
else if (op == LIR_ov)
|
||||||
|
SETO(r);
|
||||||
|
else if (op == LIR_cs)
|
||||||
|
SETC(r);
|
||||||
|
else if (op == LIR_lt)
|
||||||
|
SETL(r);
|
||||||
|
else if (op == LIR_le)
|
||||||
|
SETLE(r);
|
||||||
|
else if (op == LIR_gt)
|
||||||
|
SETG(r);
|
||||||
|
else if (op == LIR_ge)
|
||||||
|
SETGE(r);
|
||||||
|
else if (op == LIR_ult)
|
||||||
|
SETB(r);
|
||||||
|
else if (op == LIR_ule)
|
||||||
|
SETBE(r);
|
||||||
|
else if (op == LIR_ugt)
|
||||||
|
SETA(r);
|
||||||
|
else // if (op == LIR_uge)
|
||||||
|
SETAE(r);
|
||||||
|
asm_cmp(ins);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_arith(LInsp ins)
|
||||||
|
{
|
||||||
|
LOpcode op = ins->opcode();
|
||||||
|
LInsp lhs = ins->oprnd1();
|
||||||
|
LInsp rhs = ins->oprnd2();
|
||||||
|
|
||||||
|
Register rb = UnknownReg;
|
||||||
|
RegisterMask allow = GpRegs;
|
||||||
|
bool forceReg = (op == LIR_mul || !rhs->isconst());
|
||||||
|
|
||||||
|
#ifdef NANOJIT_ARM
|
||||||
|
// Arm can't do an immediate op with immediates
|
||||||
|
// outside of +/-255 (for AND) r outside of
|
||||||
|
// 0..255 for others.
|
||||||
|
if (!forceReg)
|
||||||
|
{
|
||||||
|
if (rhs->isconst() && !isU8(rhs->constval()))
|
||||||
|
forceReg = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (lhs != rhs && forceReg)
|
||||||
|
{
|
||||||
|
if ((rb = asm_binop_rhs_reg(ins)) == UnknownReg) {
|
||||||
|
rb = findRegFor(rhs, allow);
|
||||||
|
}
|
||||||
|
allow &= ~rmask(rb);
|
||||||
|
}
|
||||||
|
else if ((op == LIR_add||op == LIR_addp) && lhs->isop(LIR_alloc) && rhs->isconst()) {
|
||||||
|
// add alloc+const, use lea
|
||||||
|
Register rr = prepResultReg(ins, allow);
|
||||||
|
int d = findMemFor(lhs) + rhs->constval();
|
||||||
|
LEA(rr, d, FP);
|
||||||
|
}
|
||||||
|
|
||||||
|
Register rr = prepResultReg(ins, allow);
|
||||||
|
Reservation* rA = getresv(lhs);
|
||||||
|
Register ra;
|
||||||
|
// if this is last use of lhs in reg, we can re-use result reg
|
||||||
|
if (rA == 0 || (ra = rA->reg) == UnknownReg)
|
||||||
|
ra = findSpecificRegFor(lhs, rr);
|
||||||
|
// else, rA already has a register assigned.
|
||||||
|
|
||||||
|
if (forceReg)
|
||||||
|
{
|
||||||
|
if (lhs == rhs)
|
||||||
|
rb = ra;
|
||||||
|
|
||||||
|
if (op == LIR_add || op == LIR_addp)
|
||||||
|
ADD(rr, rb);
|
||||||
|
else if (op == LIR_sub)
|
||||||
|
SUB(rr, rb);
|
||||||
|
else if (op == LIR_mul)
|
||||||
|
MUL(rr, rb);
|
||||||
|
else if (op == LIR_and)
|
||||||
|
AND(rr, rb);
|
||||||
|
else if (op == LIR_or)
|
||||||
|
OR(rr, rb);
|
||||||
|
else if (op == LIR_xor)
|
||||||
|
XOR(rr, rb);
|
||||||
|
else if (op == LIR_lsh)
|
||||||
|
SHL(rr, rb);
|
||||||
|
else if (op == LIR_rsh)
|
||||||
|
SAR(rr, rb);
|
||||||
|
else if (op == LIR_ush)
|
||||||
|
SHR(rr, rb);
|
||||||
|
else
|
||||||
|
NanoAssertMsg(0, "Unsupported");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int c = rhs->constval();
|
||||||
|
if (op == LIR_add || op == LIR_addp) {
|
||||||
|
#ifdef NANOJIT_IA32_TODO
|
||||||
|
if (ra != rr) {
|
||||||
|
// this doesn't set cc's, only use it when cc's not required.
|
||||||
|
LEA(rr, c, ra);
|
||||||
|
ra = rr; // suppress mov
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
ADDi(rr, c);
|
||||||
|
}
|
||||||
|
} else if (op == LIR_sub) {
|
||||||
|
#ifdef NANOJIT_IA32
|
||||||
|
if (ra != rr) {
|
||||||
|
LEA(rr, -c, ra);
|
||||||
|
ra = rr;
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
SUBi(rr, c);
|
||||||
|
}
|
||||||
|
} else if (op == LIR_and)
|
||||||
|
ANDi(rr, c);
|
||||||
|
else if (op == LIR_or)
|
||||||
|
ORi(rr, c);
|
||||||
|
else if (op == LIR_xor)
|
||||||
|
XORi(rr, c);
|
||||||
|
else if (op == LIR_lsh)
|
||||||
|
SHLi(rr, c);
|
||||||
|
else if (op == LIR_rsh)
|
||||||
|
SARi(rr, c);
|
||||||
|
else if (op == LIR_ush)
|
||||||
|
SHRi(rr, c);
|
||||||
|
else
|
||||||
|
NanoAssertMsg(0, "Unsupported");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( rr != ra )
|
||||||
|
MR(rr,ra);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_neg_not(LInsp ins)
|
||||||
|
{
|
||||||
|
LOpcode op = ins->opcode();
|
||||||
|
Register rr = prepResultReg(ins, GpRegs);
|
||||||
|
|
||||||
|
LIns* lhs = ins->oprnd1();
|
||||||
|
Reservation *rA = getresv(lhs);
|
||||||
|
// if this is last use of lhs in reg, we can re-use result reg
|
||||||
|
Register ra;
|
||||||
|
if (rA == 0 || (ra=rA->reg) == UnknownReg)
|
||||||
|
ra = findSpecificRegFor(lhs, rr);
|
||||||
|
// else, rA already has a register assigned.
|
||||||
|
|
||||||
|
if (op == LIR_not)
|
||||||
|
NOT(rr);
|
||||||
|
else
|
||||||
|
NEG(rr);
|
||||||
|
|
||||||
|
if ( rr != ra )
|
||||||
|
MR(rr,ra);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_ld(LInsp ins)
|
||||||
|
{
|
||||||
|
LOpcode op = ins->opcode();
|
||||||
|
LIns* base = ins->oprnd1();
|
||||||
|
LIns* disp = ins->oprnd2();
|
||||||
|
Register rr = prepResultReg(ins, GpRegs);
|
||||||
|
int d = disp->constval();
|
||||||
|
Register ra = getBaseReg(base, d, GpRegs);
|
||||||
|
if (op == LIR_ldcb)
|
||||||
|
LD8Z(rr, d, ra);
|
||||||
|
else
|
||||||
|
LD(rr, d, ra);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_cmov(LInsp ins)
|
||||||
|
{
|
||||||
|
LOpcode op = ins->opcode();
|
||||||
|
LIns* condval = ins->oprnd1();
|
||||||
|
NanoAssert(condval->isCmp());
|
||||||
|
|
||||||
|
LIns* values = ins->oprnd2();
|
||||||
|
|
||||||
|
NanoAssert(values->opcode() == LIR_2);
|
||||||
|
LIns* iftrue = values->oprnd1();
|
||||||
|
LIns* iffalse = values->oprnd2();
|
||||||
|
|
||||||
|
NanoAssert(op == LIR_qcmov || (!iftrue->isQuad() && !iffalse->isQuad()));
|
||||||
|
|
||||||
|
const Register rr = prepResultReg(ins, GpRegs);
|
||||||
|
|
||||||
|
// this code assumes that neither LD nor MR nor MRcc set any of the condition flags.
|
||||||
|
// (This is true on Intel, is it true on all architectures?)
|
||||||
|
const Register iffalsereg = findRegFor(iffalse, GpRegs & ~rmask(rr));
|
||||||
|
if (op == LIR_cmov) {
|
||||||
|
switch (condval->opcode())
|
||||||
|
{
|
||||||
|
// note that these are all opposites...
|
||||||
|
case LIR_eq: MRNE(rr, iffalsereg); break;
|
||||||
|
case LIR_ov: MRNO(rr, iffalsereg); break;
|
||||||
|
case LIR_cs: MRNC(rr, iffalsereg); break;
|
||||||
|
case LIR_lt: MRGE(rr, iffalsereg); break;
|
||||||
|
case LIR_le: MRG(rr, iffalsereg); break;
|
||||||
|
case LIR_gt: MRLE(rr, iffalsereg); break;
|
||||||
|
case LIR_ge: MRL(rr, iffalsereg); break;
|
||||||
|
case LIR_ult: MRAE(rr, iffalsereg); break;
|
||||||
|
case LIR_ule: MRA(rr, iffalsereg); break;
|
||||||
|
case LIR_ugt: MRBE(rr, iffalsereg); break;
|
||||||
|
case LIR_uge: MRB(rr, iffalsereg); break;
|
||||||
|
debug_only( default: NanoAssert(0); break; )
|
||||||
|
}
|
||||||
|
} else if (op == LIR_qcmov) {
|
||||||
|
#if !defined NANOJIT_64BIT
|
||||||
|
NanoAssert(0);
|
||||||
|
#else
|
||||||
|
switch (condval->opcode())
|
||||||
|
{
|
||||||
|
// note that these are all opposites...
|
||||||
|
case LIR_eq: MRQNE(rr, iffalsereg); break;
|
||||||
|
case LIR_ov: MRQNO(rr, iffalsereg); break;
|
||||||
|
case LIR_cs: MRQNC(rr, iffalsereg); break;
|
||||||
|
case LIR_lt: MRQGE(rr, iffalsereg); break;
|
||||||
|
case LIR_le: MRQG(rr, iffalsereg); break;
|
||||||
|
case LIR_gt: MRQLE(rr, iffalsereg); break;
|
||||||
|
case LIR_ge: MRQL(rr, iffalsereg); break;
|
||||||
|
case LIR_ult: MRQAE(rr, iffalsereg); break;
|
||||||
|
case LIR_ule: MRQA(rr, iffalsereg); break;
|
||||||
|
case LIR_ugt: MRQBE(rr, iffalsereg); break;
|
||||||
|
case LIR_uge: MRQB(rr, iffalsereg); break;
|
||||||
|
debug_only( default: NanoAssert(0); break; )
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/*const Register iftruereg =*/ findSpecificRegFor(iftrue, rr);
|
||||||
|
asm_cmp(condval);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_qhi(LInsp ins)
|
||||||
|
{
|
||||||
|
Register rr = prepResultReg(ins, GpRegs);
|
||||||
|
LIns *q = ins->oprnd1();
|
||||||
|
int d = findMemFor(q);
|
||||||
|
LD(rr, d+4, FP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_param(LInsp ins)
|
||||||
|
{
|
||||||
|
uint32_t a = ins->imm8();
|
||||||
|
uint32_t kind = ins->imm8b();
|
||||||
|
if (kind == 0) {
|
||||||
|
// ordinary param
|
||||||
|
AbiKind abi = _thisfrag->lirbuf->abi;
|
||||||
|
uint32_t abi_regcount = abi == ABI_FASTCALL ? 2 : abi == ABI_THISCALL ? 1 : 0;
|
||||||
|
if (a < abi_regcount) {
|
||||||
|
// incoming arg in register
|
||||||
|
prepResultReg(ins, rmask(argRegs[a]));
|
||||||
|
} else {
|
||||||
|
// incoming arg is on stack, and EBP points nearby (see genPrologue)
|
||||||
|
Register r = prepResultReg(ins, GpRegs);
|
||||||
|
int d = (a - abi_regcount) * sizeof(intptr_t) + 8;
|
||||||
|
LD(r, d, FP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// saved param
|
||||||
|
prepResultReg(ins, rmask(savedRegs[a]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_short(LInsp ins)
|
||||||
|
{
|
||||||
|
Register rr = prepResultReg(ins, GpRegs);
|
||||||
|
int32_t val = ins->imm16();
|
||||||
|
if (val == 0)
|
||||||
|
XOR(rr,rr);
|
||||||
|
else
|
||||||
|
LDi(rr, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::asm_int(LInsp ins)
|
||||||
|
{
|
||||||
|
Register rr = prepResultReg(ins, GpRegs);
|
||||||
|
int32_t val = ins->imm32();
|
||||||
|
if (val == 0)
|
||||||
|
XOR(rr,rr);
|
||||||
|
else
|
||||||
|
LDi(rr, val);
|
||||||
|
}
|
||||||
|
|
||||||
void Assembler::asm_quad(LInsp ins)
|
void Assembler::asm_quad(LInsp ins)
|
||||||
{
|
{
|
||||||
#if defined NANOJIT_IA32
|
#if defined NANOJIT_IA32
|
||||||
@ -916,30 +1372,34 @@ namespace nanojit
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Assembler::asm_qlo(LInsp ins, LInsp q)
|
void Assembler::asm_qlo(LInsp ins)
|
||||||
{
|
{
|
||||||
|
LIns *q = ins->oprnd1();
|
||||||
|
|
||||||
#if defined NANOJIT_IA32
|
#if defined NANOJIT_IA32
|
||||||
if (!avmplus::AvmCore::use_sse2())
|
if (!avmplus::AvmCore::use_sse2())
|
||||||
{
|
{
|
||||||
return false;
|
Register rr = prepResultReg(ins, GpRegs);
|
||||||
|
int d = findMemFor(q);
|
||||||
|
LD(rr, d, FP);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
Reservation *resv = getresv(ins);
|
Reservation *resv = getresv(ins);
|
||||||
Register rr = resv->reg;
|
Register rr = resv->reg;
|
||||||
if (rr == UnknownReg) {
|
if (rr == UnknownReg) {
|
||||||
// store quad in spill loc
|
// store quad in spill loc
|
||||||
int d = disp(resv);
|
int d = disp(resv);
|
||||||
freeRsrcOf(ins, false);
|
freeRsrcOf(ins, false);
|
||||||
Register qr = findRegFor(q, XmmRegs);
|
Register qr = findRegFor(q, XmmRegs);
|
||||||
SSE_MOVDm(d, FP, qr);
|
SSE_MOVDm(d, FP, qr);
|
||||||
} else {
|
} else {
|
||||||
freeRsrcOf(ins, false);
|
freeRsrcOf(ins, false);
|
||||||
Register qr = findRegFor(q, XmmRegs);
|
Register qr = findRegFor(q, XmmRegs);
|
||||||
SSE_MOVD(rr,qr);
|
SSE_MOVD(rr,qr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Assembler::asm_fneg(LInsp ins)
|
void Assembler::asm_fneg(LInsp ins)
|
||||||
@ -1604,7 +2064,6 @@ namespace nanojit
|
|||||||
JMP(eip);
|
JMP(eip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* FEATURE_NANOJIT */
|
#endif /* FEATURE_NANOJIT */
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user