mirror of
https://github.com/libretro/ppsspp.git
synced 2025-02-17 23:47:40 +00:00
ARM jit: jit integer multiplies. ARM is so nice, very clean.
This commit is contained in:
parent
739b76a55a
commit
1b4394ac5e
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user