void JitILBase::subfx(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITIntegerOff); if (inst.OE) PanicAlert("OE: subfx"); IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB); val = ibuild.EmitSub(val, ibuild.EmitLoadGReg(inst.RA)); ibuild.EmitStoreGReg(val, inst.RD); if (inst.Rc) ComputeRC(ibuild, val); }
void JitILBase::rlwimix(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITIntegerOff); unsigned mask = Helper_Mask(inst.MB, inst.ME); IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS); val = ibuild.EmitRol(val, ibuild.EmitIntConst(inst.SH)); val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask)); IREmitter::InstLoc ival = ibuild.EmitLoadGReg(inst.RA); ival = ibuild.EmitAnd(ival, ibuild.EmitIntConst(~mask)); val = ibuild.EmitOr(ival, val); ibuild.EmitStoreGReg(val, inst.RA); if (inst.Rc) ComputeRC(ibuild, val); }
void JitILBase::subfcx(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITIntegerOff); if (inst.OE) PanicAlert("OE: subfcx"); IREmitter::InstLoc val, test, lhs, rhs; lhs = ibuild.EmitLoadGReg(inst.RB); rhs = ibuild.EmitLoadGReg(inst.RA); val = ibuild.EmitSub(lhs, rhs); ibuild.EmitStoreGReg(val, inst.RD); test = ibuild.EmitICmpEq(rhs, ibuild.EmitIntConst(0)); test = ibuild.EmitOr(test, ibuild.EmitICmpUgt(lhs, val)); ibuild.EmitStoreCarry(test); if (inst.Rc) ComputeRC(ibuild, val); }
void JitArm::addex(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(Integer) u32 a = inst.RA, b = inst.RB, d = inst.RD; Default(inst); return; ARMReg RA = gpr.R(a); ARMReg RB = gpr.R(b); ARMReg RD = gpr.R(d); ARMReg rA = gpr.GetReg(); GetCarryAndClear(rA); ADDS(RD, RA, RB); FinalizeCarry(rA); if (inst.Rc) ComputeRC(); gpr.Unlock(rA); }
void JitILBase::srawix(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITIntegerOff); // Shift right by two IREmitter::InstLoc input = ibuild.EmitLoadGReg(inst.RS); IREmitter::InstLoc output = ibuild.EmitSarl(input, ibuild.EmitIntConst(inst.SH)); ibuild.EmitStoreGReg(output, inst.RA); // Check whether the input is negative and any bits got shifted out. unsigned int mask = -1u << inst.SH; IREmitter::InstLoc test = ibuild.EmitOr(input, ibuild.EmitIntConst(mask & 0x7FFFFFFF)); test = ibuild.EmitICmpUgt(test, ibuild.EmitIntConst(mask)); ibuild.EmitStoreCarry(test); if (inst.Rc) ComputeRC(ibuild, output); }
void JitILBase::slwx(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITIntegerOff); IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS), samt = ibuild.EmitLoadGReg(inst.RB), corr; // FIXME: We can do better with a cmov // FIXME: We can do better on 64-bit val = ibuild.EmitShl(val, samt); corr = ibuild.EmitShl(samt, ibuild.EmitIntConst(26)); corr = ibuild.EmitSarl(corr, ibuild.EmitIntConst(31)); corr = ibuild.EmitXor(corr, ibuild.EmitIntConst(-1)); val = ibuild.EmitAnd(corr, val); ibuild.EmitStoreGReg(val, inst.RA); if (inst.Rc) ComputeRC(ibuild, val); }
void JitArm::subfx(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(Integer) u32 a = inst.RA, b = inst.RB, d = inst.RD; if (inst.OE) PanicAlert("OE: subfx"); if (gpr.IsImm(a) && gpr.IsImm(b)) { gpr.SetImmediate(d, gpr.GetImm(b) - gpr.GetImm(a)); if (inst.Rc) ComputeRC(gpr.GetImm(d), 0); return; } ARMReg RA = gpr.R(a); ARMReg RB = gpr.R(b); ARMReg RD = gpr.R(d); SUBS(RD, RB, RA); if (inst.Rc) GenerateRC(); }
void Jit64::regimmop(int d, int a, bool binary, u32 value, Operation doop, void (XEmitter::*op)(int, const Gen::OpArg&, const Gen::OpArg&), bool Rc, bool carry) { gpr.Lock(d, a); if (a || binary || carry) // yeh nasty special case addic { if (gpr.R(a).IsImm() && !carry) { gpr.SetImmediate32(d, doop((u32)gpr.R(a).offset, value)); } else if (a == d) { gpr.KillImmediate(d, true, true); (this->*op)(32, gpr.R(d), Imm32(value)); //m_GPR[d] = m_GPR[_inst.RA] + _inst.SIMM_16; if (carry) GenerateCarry(); } else { gpr.BindToRegister(d, false); MOV(32, gpr.R(d), gpr.R(a)); (this->*op)(32, gpr.R(d), Imm32(value)); //m_GPR[d] = m_GPR[_inst.RA] + _inst.SIMM_16; if (carry) GenerateCarry(); } } else if (doop == Add) { // a == 0, which for these instructions imply value = 0 gpr.SetImmediate32(d, value); } else { _assert_msg_(DYNA_REC, 0, "WTF regimmop"); } if (Rc) { ComputeRC(gpr.R(d)); } gpr.UnlockAll(); }
void JitILBase::addex(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITIntegerOff); IREmitter::InstLoc a = ibuild.EmitLoadGReg(inst.RA); IREmitter::InstLoc b = ibuild.EmitLoadGReg(inst.RB); IREmitter::InstLoc ab = ibuild.EmitAdd(a, b); IREmitter::InstLoc new_carry = ibuild.EmitICmpUlt(ab, a); IREmitter::InstLoc previous_carry = ibuild.EmitLoadCarry(); IREmitter::InstLoc abc = ibuild.EmitAdd(ab, previous_carry); new_carry = ibuild.EmitOr(new_carry, ibuild.EmitICmpUlt(abc, ab)); ibuild.EmitStoreGReg(abc, inst.RD); ibuild.EmitStoreCarry(new_carry); if (inst.OE) PanicAlert("OE: addex"); if (inst.Rc) ComputeRC(ibuild, abc); }
void JitILBase::reg_imm(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITIntegerOff); int d = inst.RD, a = inst.RA, s = inst.RS; IREmitter::InstLoc val, test, c; switch (inst.OPCD) { case 14: // addi val = ibuild.EmitIntConst(inst.SIMM_16); if (a) val = ibuild.EmitAdd(ibuild.EmitLoadGReg(a), val); ibuild.EmitStoreGReg(val, d); break; case 15: // addis val = ibuild.EmitIntConst(inst.SIMM_16 << 16); if (a) val = ibuild.EmitAdd(ibuild.EmitLoadGReg(a), val); ibuild.EmitStoreGReg(val, d); break; case 24: // ori val = ibuild.EmitIntConst(inst.UIMM); val = ibuild.EmitOr(ibuild.EmitLoadGReg(s), val); ibuild.EmitStoreGReg(val, a); break; case 25: // oris val = ibuild.EmitIntConst(inst.UIMM << 16); val = ibuild.EmitOr(ibuild.EmitLoadGReg(s), val); ibuild.EmitStoreGReg(val, a); break; case 28: // andi val = ibuild.EmitIntConst(inst.UIMM); val = ibuild.EmitAnd(ibuild.EmitLoadGReg(s), val); ibuild.EmitStoreGReg(val, a); ComputeRC(ibuild, val); break; case 29: // andis val = ibuild.EmitIntConst(inst.UIMM << 16); val = ibuild.EmitAnd(ibuild.EmitLoadGReg(s), val); ibuild.EmitStoreGReg(val, a); ComputeRC(ibuild, val); break; case 26: // xori val = ibuild.EmitIntConst(inst.UIMM); val = ibuild.EmitXor(ibuild.EmitLoadGReg(s), val); ibuild.EmitStoreGReg(val, a); break; case 27: // xoris val = ibuild.EmitIntConst(inst.UIMM << 16); val = ibuild.EmitXor(ibuild.EmitLoadGReg(s), val); ibuild.EmitStoreGReg(val, a); break; case 12: // addic case 13: // addic_rc c = ibuild.EmitIntConst(inst.SIMM_16); val = ibuild.EmitAdd(ibuild.EmitLoadGReg(a), c); ibuild.EmitStoreGReg(val, d); test = ibuild.EmitICmpUgt(c, val); ibuild.EmitStoreCarry(test); if (inst.OPCD == 13) ComputeRC(ibuild, val); break; default: FALLBACK_IF(true); } }