ARM jit: jit integer multiplies. ARM is so nice, very clean.

This commit is contained in:
Henrik Rydgard 2013-01-30 01:06:14 +01:00
parent 739b76a55a
commit 1b4394ac5e
5 changed files with 78 additions and 6 deletions

View File

@ -453,6 +453,21 @@ void ARMXEmitter::MULS(ARMReg dest, ARMReg src, ARMReg op2)
{
Write32(condition | (1 << 20) | (dest << 16) | (src << 8) | (9 << 4) | op2);
}
void ARMXEmitter::Write4OpMultiply(u32 op, ARMReg destLo, ARMReg destHi, ARMReg rm, ARMReg rn) {
Write32(condition | (op << 20) | (destHi << 16) | (destLo << 12) | (rm << 8) | (9 << 4) | rn);
}
void ARMXEmitter::UMULL(ARMReg destLo, ARMReg destHi, ARMReg rm, ARMReg rn)
{
Write4OpMultiply(0x8, destLo, destHi, rn, rm);
}
void ARMXEmitter::SMULL(ARMReg destLo, ARMReg destHi, ARMReg rm, ARMReg rn)
{
Write4OpMultiply(0xC, destLo, destHi, rn, rm);
}
void ARMXEmitter::SXTB (ARMReg dest, ARMReg op2)
{
Write32(condition | (0x6AF << 16) | (dest << 12) | (7 << 4) | op2);

View File

@ -333,6 +333,9 @@ private:
void WriteShiftedDataOp(u32 op, bool SetFlags, ARMReg dest, ARMReg src, Operand2 op2);
void WriteSignedMultiply(u32 Op, u32 Op2, u32 Op3, ARMReg dest, ARMReg r1, ARMReg r2);
void Write4OpMultiply(u32 op, ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm);
// New Ops
void WriteInstruction(u32 op, ARMReg Rd, ARMReg Rn, Operand2 Rm, bool SetFlags = false);
@ -439,6 +442,10 @@ public:
void MUL (ARMReg dest, ARMReg src, ARMReg op2);
void MULS(ARMReg dest, ARMReg src, ARMReg op2);
void UMULL(ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm);
void SMULL(ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm);
void SXTB(ARMReg dest, ARMReg op2);
void SXTH(ARMReg dest, ARMReg op2, u8 rotation = 0);
void SXTAH(ARMReg dest, ARMReg src, ARMReg op2, u8 rotation = 0);

View File

@ -115,7 +115,6 @@ namespace MIPSComp
case 11: // R(rt) = R(rs) < uimm; break; //sltiu
{
LogBlockNumber();
gpr.MapDirtyIn(rt, rs);
Operand2 op2;
bool negated;
@ -310,7 +309,45 @@ namespace MIPSComp
void Jit::Comp_MulDivType(u32 op)
{
DISABLE;
// DISABLE;
int rt = _RT;
int rs = _RS;
int rd = _RD;
switch (op & 63)
{
case 16: // R(rd) = HI; //mfhi
gpr.MapDirtyIn(rd, MIPSREG_HI);
MOV(gpr.R(rd), gpr.R(MIPSREG_HI));
break;
case 17: // HI = R(rs); //mthi
gpr.MapDirtyIn(MIPSREG_HI, rs);
MOV(gpr.R(MIPSREG_HI), gpr.R(rs));
break;
case 18: // R(rd) = LO; break; //mflo
gpr.MapDirtyIn(rd, MIPSREG_LO);
MOV(gpr.R(rd), gpr.R(MIPSREG_LO));
break;
case 19: // LO = R(rs); break; //mtlo
gpr.MapDirtyIn(MIPSREG_LO, rs);
MOV(gpr.R(MIPSREG_LO), gpr.R(rs));
break;
case 24: //mult (the most popular one). lo,hi = signed mul (rs * rt)
gpr.MapDirtyDirtyInIn(MIPSREG_LO, MIPSREG_HI, rs, rt);
SMULL(gpr.R(MIPSREG_LO), gpr.R(MIPSREG_HI), gpr.R(rs), gpr.R(rt));
break;
case 25: //multu (2nd) lo,hi = unsigned mul (rs * rt)
gpr.MapDirtyDirtyInIn(MIPSREG_LO, MIPSREG_HI, rs, rt);
UMULL(gpr.R(MIPSREG_LO), gpr.R(MIPSREG_HI), gpr.R(rs), gpr.R(rt));
default:
DISABLE;
}
}
}

View File

@ -83,7 +83,7 @@ allocate:
if (!(mapFlags & MAP_NOINIT)) {
if (mr[mipsReg].loc == ML_MEM) {
if (mipsReg != 0) {
emit->LDR((ARMReg)reg, CTXREG, 4 * mipsReg);
emit->LDR((ARMReg)reg, CTXREG, GetMipsRegOffset(mipsReg));
} else {
// If we get a request to load the zero register, at least we won't spend
// time on a memory access...
@ -148,6 +148,17 @@ void ArmRegCache::MapDirtyInIn(MIPSReg rd, MIPSReg rs, MIPSReg rt, bool avoidLoa
ReleaseSpillLocks();
}
void ArmRegCache::MapDirtyDirtyInIn(MIPSReg rd1, MIPSReg rd2, MIPSReg rs, MIPSReg rt, bool avoidLoad) {
SpillLock(rd1, rd2, rs, rt);
bool overlap1 = avoidLoad && (rd1 == rs || rd1 == rt);
bool overlap2 = avoidLoad && (rd2 == rs || rd2 == rt);
MapReg(rd1, MAP_DIRTY | (overlap1 ? 0 : MAP_NOINIT));
MapReg(rd2, MAP_DIRTY | (overlap2 ? 0 : MAP_NOINIT));
MapReg(rt);
MapReg(rs);
ReleaseSpillLocks();
}
void ArmRegCache::FlushArmReg(ARMReg r) {
if (ar[r].mipsReg == -1) {
// Nothing to do, reg not mapped.
@ -155,7 +166,7 @@ void ArmRegCache::FlushArmReg(ARMReg r) {
}
if (ar[r].mipsReg != -1) {
if (ar[r].isDirty && mr[ar[r].mipsReg].loc == ML_ARMREG)
emit->STR(CTXREG, r, 4 * ar[r].mipsReg);
emit->STR(CTXREG, r, GetMipsRegOffset(ar[r].mipsReg));
// IMMs won't be in an ARM reg.
mr[ar[r].mipsReg].loc = ML_MEM;
mr[ar[r].mipsReg].reg = INVALID_REG;
@ -246,10 +257,11 @@ int ArmRegCache::GetMipsRegOffset(MIPSReg r) {
return 0; // or what?
}
void ArmRegCache::SpillLock(MIPSReg r1, MIPSReg r2, MIPSReg r3) {
void ArmRegCache::SpillLock(MIPSReg r1, MIPSReg r2, MIPSReg r3, MIPSReg r4) {
mr[r1].spillLock = true;
if (r2 != -1) mr[r2].spillLock = true;
if (r3 != -1) mr[r3].spillLock = true;
if (r4 != -1) mr[r4].spillLock = true;
}
void ArmRegCache::ReleaseSpillLocks() {

View File

@ -77,7 +77,7 @@ public:
// Protect the arm register containing a MIPS register from spilling, to ensure that
// it's being kept allocated.
void SpillLock(MIPSReg reg, MIPSReg reg2 = -1, MIPSReg reg3 = -1);
void SpillLock(MIPSReg reg, MIPSReg reg2 = -1, MIPSReg reg3 = -1, MIPSReg reg4 = -1);
void ReleaseSpillLocks();
void SetImm(MIPSReg reg, u32 immVal);
@ -89,6 +89,7 @@ public:
void MapInIn(MIPSReg rd, MIPSReg rs);
void MapDirtyIn(MIPSReg rd, MIPSReg rs, bool avoidLoad = true);
void MapDirtyInIn(MIPSReg rd, MIPSReg rs, MIPSReg rt, bool avoidLoad = true);
void MapDirtyDirtyInIn(MIPSReg rd1, MIPSReg rd2, MIPSReg rs, MIPSReg rt, bool avoidLoad = true);
void FlushArmReg(ARMReg r);
void FlushMipsReg(MIPSReg r);