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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
Fragment *frag = lr->target;
|
||||
@ -1116,19 +1062,15 @@ namespace nanojit
|
||||
break;
|
||||
}
|
||||
case LIR_short:
|
||||
{
|
||||
countlir_imm();
|
||||
asm_short(ins);
|
||||
break;
|
||||
}
|
||||
case LIR_int:
|
||||
{
|
||||
countlir_imm();
|
||||
Register rr = prepResultReg(ins, GpRegs);
|
||||
int32_t val;
|
||||
if (op == LIR_int)
|
||||
val = ins->imm32();
|
||||
else
|
||||
val = ins->imm16();
|
||||
if (val == 0)
|
||||
XOR(rr,rr);
|
||||
else
|
||||
LDi(rr, val);
|
||||
asm_int(ins);
|
||||
break;
|
||||
}
|
||||
case LIR_quad:
|
||||
@ -1150,132 +1092,36 @@ namespace nanojit
|
||||
case LIR_param:
|
||||
{
|
||||
countlir_param();
|
||||
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]));
|
||||
}
|
||||
asm_param(ins);
|
||||
break;
|
||||
}
|
||||
case LIR_qlo:
|
||||
{
|
||||
countlir_qlo();
|
||||
LIns *q = ins->oprnd1();
|
||||
|
||||
if (!asm_qlo(ins, q))
|
||||
{
|
||||
Register rr = prepResultReg(ins, GpRegs);
|
||||
int d = findMemFor(q);
|
||||
LD(rr, d, FP);
|
||||
}
|
||||
asm_qlo(ins);
|
||||
break;
|
||||
}
|
||||
}
|
||||
case LIR_qhi:
|
||||
{
|
||||
countlir_qhi();
|
||||
Register rr = prepResultReg(ins, GpRegs);
|
||||
LIns *q = ins->oprnd1();
|
||||
int d = findMemFor(q);
|
||||
LD(rr, d+4, FP);
|
||||
asm_qhi(ins);
|
||||
break;
|
||||
}
|
||||
|
||||
case LIR_qcmov:
|
||||
case LIR_cmov:
|
||||
{
|
||||
countlir_cmov();
|
||||
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);
|
||||
asm_cmov(ins);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
case LIR_ld:
|
||||
case LIR_ldc:
|
||||
case LIR_ldcb:
|
||||
{
|
||||
countlir_ld();
|
||||
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);
|
||||
asm_ld(ins);
|
||||
break;
|
||||
}
|
||||
|
||||
case LIR_ldq:
|
||||
case LIR_ldqc:
|
||||
{
|
||||
@ -1283,31 +1129,13 @@ namespace nanojit
|
||||
asm_load64(ins);
|
||||
break;
|
||||
}
|
||||
|
||||
case LIR_neg:
|
||||
case LIR_not:
|
||||
{
|
||||
countlir_alu();
|
||||
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);
|
||||
asm_neg_not(ins);
|
||||
break;
|
||||
}
|
||||
|
||||
case LIR_qjoin:
|
||||
{
|
||||
countlir_qjoin();
|
||||
@ -1338,115 +1166,7 @@ namespace nanojit
|
||||
case LIR_ush:
|
||||
{
|
||||
countlir_alu();
|
||||
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);
|
||||
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);
|
||||
asm_arith(ins);
|
||||
break;
|
||||
}
|
||||
#ifndef NJ_SOFTFLOAT
|
||||
@ -1622,28 +1342,10 @@ namespace nanojit
|
||||
case LIR_loop:
|
||||
{
|
||||
countlir_loop();
|
||||
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()]);
|
||||
asm_loop(ins, loopJumps);
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef NJ_SOFTFLOAT
|
||||
case LIR_feq:
|
||||
case LIR_fle:
|
||||
@ -1652,17 +1354,7 @@ namespace nanojit
|
||||
case LIR_fge:
|
||||
{
|
||||
countlir_fpu();
|
||||
// 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);
|
||||
asm_fcond(ins);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@ -1679,36 +1371,10 @@ namespace nanojit
|
||||
case LIR_uge:
|
||||
{
|
||||
countlir_alu();
|
||||
// only want certain regs
|
||||
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);
|
||||
asm_cond(ins);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
#ifndef NJ_SOFTFLOAT
|
||||
case LIR_fcall:
|
||||
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()
|
||||
{
|
||||
// restore saved regs
|
||||
@ -1867,6 +1466,7 @@ namespace nanojit
|
||||
return;
|
||||
|
||||
#ifdef NANOJIT_ARM
|
||||
// @todo Why is there here?!? This routine should be indep. of platform
|
||||
verbose_only(
|
||||
if (_verbose) {
|
||||
char* s = &outline[0];
|
||||
|
@ -296,7 +296,18 @@ namespace nanojit
|
||||
void asm_pusharg(LInsp p);
|
||||
NIns* asm_adjustBranch(NIns* at, NIns* target);
|
||||
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_fop(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)
|
||||
{
|
||||
if (sz == ARGSIZE_Q)
|
||||
@ -646,13 +1120,6 @@ Assembler::asm_quad(LInsp ins)
|
||||
//asm_output("<<< asm_quad");
|
||||
}
|
||||
|
||||
bool
|
||||
Assembler::asm_qlo(LInsp ins, LInsp q)
|
||||
{
|
||||
(void)ins; (void)q;
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
Assembler::asm_nongp_copy(Register r, Register s)
|
||||
{
|
||||
|
@ -350,6 +350,7 @@ namespace nanojit
|
||||
asm_mmq(rb, dr, FP, da);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::asm_quad(LInsp 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;
|
||||
return false;
|
||||
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_nongp_copy(Register r, Register s)
|
||||
|
@ -825,6 +825,462 @@ namespace nanojit
|
||||
#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)
|
||||
{
|
||||
#if defined NANOJIT_IA32
|
||||
@ -916,30 +1372,34 @@ namespace nanojit
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Assembler::asm_qlo(LInsp ins, LInsp q)
|
||||
void Assembler::asm_qlo(LInsp ins)
|
||||
{
|
||||
LIns *q = ins->oprnd1();
|
||||
|
||||
#if defined NANOJIT_IA32
|
||||
if (!avmplus::AvmCore::use_sse2())
|
||||
{
|
||||
return false;
|
||||
Register rr = prepResultReg(ins, GpRegs);
|
||||
int d = findMemFor(q);
|
||||
LD(rr, d, FP);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
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);
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Assembler::asm_fneg(LInsp ins)
|
||||
@ -1604,7 +2064,6 @@ namespace nanojit
|
||||
JMP(eip);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif /* FEATURE_NANOJIT */
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user