mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-30 17:02:19 +00:00
x86jit: Implement shifts.
This commit is contained in:
parent
601bf344c1
commit
363f2b68e1
@ -698,6 +698,10 @@ void IRNativeRegCacheBase::ApplyMapping(const Mapping *mapping, int count) {
|
||||
}
|
||||
}
|
||||
|
||||
auto isNoinit = [](MIPSMap f) {
|
||||
return (f & MIPSMap::NOINIT) == MIPSMap::NOINIT;
|
||||
};
|
||||
|
||||
auto mapRegs = [&](int i) {
|
||||
MIPSLoc type = MIPSLoc::MEM;
|
||||
switch (mapping[i].type) {
|
||||
@ -714,24 +718,39 @@ void IRNativeRegCacheBase::ApplyMapping(const Mapping *mapping, int count) {
|
||||
return;
|
||||
}
|
||||
|
||||
MIPSMap flags = mapping[i].flags;
|
||||
for (int j = 0; j < count; ++j) {
|
||||
if (mapping[j].type == mapping[i].type && mapping[j].reg == mapping[i].reg && i != j) {
|
||||
_assert_msg_(mapping[j].lanes == mapping[i].lanes, "Lane aliasing not supported yet");
|
||||
|
||||
if (!isNoinit(mapping[j].flags) && isNoinit(flags)) {
|
||||
flags = (flags & MIPSMap::BACKEND_MASK) | MIPSMap::DIRTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (config_.mapFPUSIMD || mapping[i].type == 'G') {
|
||||
MapNativeReg(type, mapping[i].reg, mapping[i].lanes, mapping[i].flags);
|
||||
MapNativeReg(type, mapping[i].reg, mapping[i].lanes, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int j = 0; j < mapping[i].lanes; ++j)
|
||||
MapNativeReg(type, mapping[i].reg + j, 1, mapping[i].flags);
|
||||
MapNativeReg(type, mapping[i].reg + j, 1, flags);
|
||||
};
|
||||
auto mapFilteredRegs = [&](auto pred) {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (pred(mapping[i].flags))
|
||||
mapRegs(i);
|
||||
}
|
||||
};
|
||||
|
||||
// Do two passes: first any without NOINIT, then NOINIT.
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if ((mapping[i].flags & MIPSMap::NOINIT) != MIPSMap::NOINIT)
|
||||
mapRegs(i);
|
||||
}
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if ((mapping[i].flags & MIPSMap::NOINIT) == MIPSMap::NOINIT)
|
||||
mapRegs(i);
|
||||
}
|
||||
// Do two passes: with backend special flags, and without.
|
||||
mapFilteredRegs([](MIPSMap flags) {
|
||||
return (flags & MIPSMap::BACKEND_MASK) != MIPSMap::INIT;
|
||||
});
|
||||
mapFilteredRegs([](MIPSMap flags) {
|
||||
return (flags & MIPSMap::BACKEND_MASK) == MIPSMap::INIT;
|
||||
});
|
||||
}
|
||||
|
||||
void IRNativeRegCacheBase::CleanupMapping(const Mapping *mapping, int count) {
|
||||
|
@ -79,6 +79,8 @@ enum class MIPSMap : uint8_t {
|
||||
INIT = 0,
|
||||
DIRTY = 1,
|
||||
NOINIT = 2 | DIRTY,
|
||||
|
||||
BACKEND_MASK = 0xF0,
|
||||
};
|
||||
static inline MIPSMap operator |(const MIPSMap &lhs, const MIPSMap &rhs) {
|
||||
return MIPSMap((uint8_t)lhs | (uint8_t)rhs);
|
||||
|
@ -365,10 +365,74 @@ void X64JitBackend::CompIR_Shift(IRInst inst) {
|
||||
|
||||
switch (inst.op) {
|
||||
case IROp::Shl:
|
||||
if (cpu_info.bBMI2) {
|
||||
regs_.Map(inst);
|
||||
SHLX(32, regs_.RX(inst.dest), regs_.R(inst.src1), regs_.RX(inst.src2));
|
||||
} else {
|
||||
regs_.MapWithFlags(inst, X64Map::NONE, X64Map::NONE, X64Map::SHIFT);
|
||||
if (inst.dest == inst.src1) {
|
||||
SHL(32, regs_.R(inst.dest), regs_.R(inst.src2));
|
||||
} else if (inst.dest == inst.src2) {
|
||||
MOV(32, R(SCRATCH1), regs_.R(inst.src1));
|
||||
SHL(32, R(SCRATCH1), regs_.R(inst.src2));
|
||||
MOV(32, regs_.R(inst.dest), R(SCRATCH1));
|
||||
} else {
|
||||
MOV(32, regs_.R(inst.dest), regs_.R(inst.src1));
|
||||
SHL(32, regs_.R(inst.dest), regs_.R(inst.src2));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case IROp::Shr:
|
||||
if (cpu_info.bBMI2) {
|
||||
regs_.Map(inst);
|
||||
SHRX(32, regs_.RX(inst.dest), regs_.R(inst.src1), regs_.RX(inst.src2));
|
||||
} else {
|
||||
regs_.MapWithFlags(inst, X64Map::NONE, X64Map::NONE, X64Map::SHIFT);
|
||||
if (inst.dest == inst.src1) {
|
||||
SHR(32, regs_.R(inst.dest), regs_.R(inst.src2));
|
||||
} else if (inst.dest == inst.src2) {
|
||||
MOV(32, R(SCRATCH1), regs_.R(inst.src1));
|
||||
SHR(32, R(SCRATCH1), regs_.R(inst.src2));
|
||||
MOV(32, regs_.R(inst.dest), R(SCRATCH1));
|
||||
} else {
|
||||
MOV(32, regs_.R(inst.dest), regs_.R(inst.src1));
|
||||
SHR(32, regs_.R(inst.dest), regs_.R(inst.src2));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case IROp::Sar:
|
||||
if (cpu_info.bBMI2) {
|
||||
regs_.Map(inst);
|
||||
SARX(32, regs_.RX(inst.dest), regs_.R(inst.src1), regs_.RX(inst.src2));
|
||||
} else {
|
||||
regs_.MapWithFlags(inst, X64Map::NONE, X64Map::NONE, X64Map::SHIFT);
|
||||
if (inst.dest == inst.src1) {
|
||||
SAR(32, regs_.R(inst.dest), regs_.R(inst.src2));
|
||||
} else if (inst.dest == inst.src2) {
|
||||
MOV(32, R(SCRATCH1), regs_.R(inst.src1));
|
||||
SAR(32, R(SCRATCH1), regs_.R(inst.src2));
|
||||
MOV(32, regs_.R(inst.dest), R(SCRATCH1));
|
||||
} else {
|
||||
MOV(32, regs_.R(inst.dest), regs_.R(inst.src1));
|
||||
SAR(32, regs_.R(inst.dest), regs_.R(inst.src2));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case IROp::Ror:
|
||||
CompIR_Generic(inst);
|
||||
regs_.MapWithFlags(inst, X64Map::NONE, X64Map::NONE, X64Map::SHIFT);
|
||||
if (inst.dest == inst.src1) {
|
||||
ROR(32, regs_.R(inst.dest), regs_.R(inst.src2));
|
||||
} else if (inst.dest == inst.src2) {
|
||||
MOV(32, R(SCRATCH1), regs_.R(inst.src1));
|
||||
ROR(32, R(SCRATCH1), regs_.R(inst.src2));
|
||||
MOV(32, regs_.R(inst.dest), R(SCRATCH1));
|
||||
} else {
|
||||
MOV(32, regs_.R(inst.dest), regs_.R(inst.src1));
|
||||
ROR(32, regs_.R(inst.dest), regs_.R(inst.src2));
|
||||
}
|
||||
break;
|
||||
|
||||
case IROp::ShlImm:
|
||||
@ -431,6 +495,9 @@ void X64JitBackend::CompIR_Shift(IRInst inst) {
|
||||
regs_.Map(inst);
|
||||
MOV(32, regs_.R(inst.dest), regs_.R(inst.src1));
|
||||
}
|
||||
} else if (cpu_info.bBMI2) {
|
||||
regs_.Map(inst);
|
||||
RORX(32, regs_.RX(inst.dest), regs_.R(inst.src1), inst.src2 & 31);
|
||||
} else {
|
||||
regs_.Map(inst);
|
||||
if (inst.dest != inst.src1)
|
||||
|
@ -63,8 +63,14 @@ const int *X64IRRegCache::GetAllocationOrder(MIPSLoc type, MIPSMap flags, int &c
|
||||
#endif
|
||||
};
|
||||
|
||||
if ((flags & X64Map::MASK) == X64Map::SHIFT) {
|
||||
// It's a single option for shifts.
|
||||
static const int shiftReg[] = { ECX };
|
||||
count = 1;
|
||||
return shiftReg;
|
||||
}
|
||||
#if PPSSPP_ARCH(X86)
|
||||
if ((flags & X64Map::LOW_SUBREG) == X64Map::LOW_SUBREG) {
|
||||
if ((flags & X64Map::MASK) == X64Map::LOW_SUBREG) {
|
||||
static const int lowSubRegAllocationOrder[] = {
|
||||
EDX, EBX, ECX,
|
||||
};
|
||||
@ -132,7 +138,17 @@ X64Reg X64IRRegCache::TryMapTempImm(IRReg r, X64Map flags) {
|
||||
_dbg_assert_(IsValidGPR(r));
|
||||
|
||||
auto canUseReg = [flags](X64Reg r) {
|
||||
return (flags & X64Map::LOW_SUBREG) != X64Map::LOW_SUBREG || HasLowSubregister(r);
|
||||
switch (flags & X64Map::MASK) {
|
||||
case X64Map::NONE:
|
||||
return true;
|
||||
case X64Map::LOW_SUBREG:
|
||||
return HasLowSubregister(r);
|
||||
case X64Map::SHIFT:
|
||||
return r == RCX;
|
||||
default:
|
||||
_assert_msg_(false, "Unexpected flags");
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// If already mapped, no need for a temporary.
|
||||
@ -175,6 +191,30 @@ void X64IRRegCache::MapWithFlags(IRInst inst, X64Map destFlags, X64Map src1Flags
|
||||
mapping[1].flags = mapping[1].flags | src1Flags;
|
||||
mapping[2].flags = mapping[2].flags | src2Flags;
|
||||
|
||||
auto flushReg = [&](IRNativeReg nreg) {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (mapping[i].reg == nr[nreg].mipsReg && (mapping[i].flags & MIPSMap::NOINIT) == MIPSMap::NOINIT) {
|
||||
DiscardNativeReg(nreg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
FlushNativeReg(nreg);
|
||||
};
|
||||
|
||||
// If there are any special rules, we might need to spill.
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
switch (mapping[i].flags & X64Map::MASK) {
|
||||
case X64Map::SHIFT:
|
||||
if (nr[RCX].mipsReg != mapping[i].reg)
|
||||
flushReg(RCX);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ApplyMapping(mapping, 3);
|
||||
CleanupMapping(mapping, 3);
|
||||
}
|
||||
|
@ -44,6 +44,8 @@ static constexpr auto pcOffset = offsetof(MIPSState, pc) - 128;
|
||||
enum class X64Map : uint8_t {
|
||||
NONE = 0,
|
||||
LOW_SUBREG = 0x10,
|
||||
SHIFT = 0x20,
|
||||
MASK = 0xF0,
|
||||
};
|
||||
static inline MIPSMap operator |(const MIPSMap &lhs, const X64Map &rhs) {
|
||||
return MIPSMap((uint8_t)lhs | (uint8_t)rhs);
|
||||
|
Loading…
Reference in New Issue
Block a user