mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
loongarch: Fix various IR JIT & VertexJIT bugs
This commit is contained in:
1 parent
28d2bd5b0d
commit
24c6647ce3
8 files changed
+50
-37
No files matched your search
@@ -15,7 +15,6 @@
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
|
||||
#include "ppsspp_config.h"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
@@ -1751,11 +1750,10 @@ void LoongArch64Emitter::SetJumpTarget(FixupBranch &branch, const void *dst) {
|
||||
|
||||
u32 fixup;
|
||||
|
||||
_assert_msg_((dstp & 3) == 0, "Destination should be aligned (no compressed)");
|
||||
_assert_msg_((dstp & 3) == 0, "Destination should be aligned");
|
||||
|
||||
ptrdiff_t distance = dstp - srcp;
|
||||
_assert_msg_((distance & 3) == 0, "Distance should be aligned (no compressed)");
|
||||
|
||||
_assert_msg_((distance & 3) == 0, "Distance should be aligned");
|
||||
switch (branch.type) {
|
||||
case FixupBranchType::B:
|
||||
_assert_msg_(BranchInRange(branch.ptr, dst), "B destination is too far away (%p -> %p)", branch.ptr, dst);
|
||||
@@ -1817,12 +1815,12 @@ void LoongArch64Emitter::QuickJump(LoongArch64Reg scratchreg, LoongArch64Reg rd,
|
||||
if (!JumpInRange(GetCodePointer(), dst)) {
|
||||
int32_t lower = (int32_t)SignReduce64((int64_t)dst, 18);
|
||||
static_assert(sizeof(intptr_t) <= sizeof(int64_t));
|
||||
LI(scratchreg, dst - lower);
|
||||
LI(scratchreg, dst - lower);
|
||||
JIRL(rd, scratchreg, lower);
|
||||
} else if (rd != R_ZERO) {
|
||||
} else if (rd == R_RA) {
|
||||
BL(dst);
|
||||
} else {
|
||||
B(dst);
|
||||
B(dst);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -75,6 +75,10 @@ void LoongArch64JitBackend::GenerateFixedCode(MIPSState *mipsState) {
|
||||
{
|
||||
// LoongArch64 does not have any flush to zero capability, so leaving it off
|
||||
LD_WU(SCRATCH2, CTXREG, offsetof(MIPSState, fcr31));
|
||||
// We have to do this because otherwise, FMUL will output inaccurate results,
|
||||
// which cause some game going into infinite loop, for example PATAPON.
|
||||
ANDI(SCRATCH2, SCRATCH2, 3);
|
||||
SLLI_D(SCRATCH2, SCRATCH2, 8);
|
||||
|
||||
// We can skip if the rounding mode is nearest (0) and flush is not set.
|
||||
// (as restoreRoundingMode cleared it out anyway)
|
||||
|
||||
@@ -559,7 +559,11 @@ void LoongArch64JitBackend::CompIR_FSpecial(IRInst inst) {
|
||||
// It might be in a non-volatile register.
|
||||
// TODO: May have to handle a transfer if SIMD here.
|
||||
if (regs_.IsFPRMapped(inst.src1)) {
|
||||
FMOV_S(F0, regs_.F(inst.src1));
|
||||
int lane = regs_.GetFPRLane(inst.src1);
|
||||
if (lane == 0)
|
||||
FMOV_S(F0, regs_.F(inst.src1));
|
||||
else
|
||||
VREPLVEI_W(V0, regs_.V(inst.src1), lane);
|
||||
} else {
|
||||
int offset = offsetof(MIPSState, f) + inst.src1 * 4;
|
||||
FLD_S(F0, CTXREG, offset);
|
||||
|
||||
@@ -97,7 +97,7 @@ void LoongArch64JitBackend::CompIR_Transfer(IRInst inst) {
|
||||
|
||||
case IROp::SetCtrlVFPUFReg:
|
||||
regs_.Map(inst);
|
||||
MOVGR2FR_W(regs_.R(IRREG_VFPU_CTRL_BASE + inst.dest), regs_.F(inst.src1));
|
||||
MOVFR2GR_S(regs_.R(IRREG_VFPU_CTRL_BASE + inst.dest), regs_.F(inst.src1));
|
||||
regs_.MarkGPRDirty(IRREG_VFPU_CTRL_BASE + inst.dest, true);
|
||||
break;
|
||||
|
||||
@@ -117,7 +117,8 @@ void LoongArch64JitBackend::CompIR_Transfer(IRInst inst) {
|
||||
LI(SCRATCH1, 0x0181FFFF);
|
||||
AND(SCRATCH1, regs_.R(inst.src1), SCRATCH1);
|
||||
// Extract the new fpcond value.
|
||||
BSTRPICK_D(regs_.R(IRREG_FPCOND), regs_.R(IRREG_FPCOND), 23, 23);
|
||||
SRLI_D(regs_.R(IRREG_FPCOND), SCRATCH1, 23);
|
||||
ANDI(regs_.R(IRREG_FPCOND), regs_.R(IRREG_FPCOND), 1);
|
||||
ST_W(SCRATCH1, CTXREG, IRREG_FCR31 * 4);
|
||||
regs_.MarkGPRDirty(IRREG_FPCOND, true);
|
||||
break;
|
||||
@@ -149,7 +150,6 @@ void LoongArch64JitBackend::CompIR_Transfer(IRInst inst) {
|
||||
if (regs_.IsGPRImm(inst.src1) && regs_.GetGPRImm(inst.src1) == 0) {
|
||||
regs_.MapFPR(inst.dest, MIPSMap::NOINIT);
|
||||
MOVGR2FR_W(regs_.F(inst.dest), R_ZERO);
|
||||
FFINT_S_W(regs_.F(inst.dest), regs_.F(inst.dest));
|
||||
} else {
|
||||
regs_.Map(inst);
|
||||
MOVGR2FR_W(regs_.F(inst.dest), regs_.R(inst.src1));
|
||||
|
||||
@@ -219,19 +219,20 @@ void LoongArch64JitBackend::CompIR_VecAssign(IRInst inst) {
|
||||
case IROp::Vec4Blend:
|
||||
regs_.Map(inst);
|
||||
if (cpu_info.LOONGARCH_LSX) {
|
||||
LoongArch64Reg src = regs_.V(inst.src1);;
|
||||
IRReg src = inst.src1;
|
||||
uint8_t imm = inst.constant;
|
||||
if (inst.dest == inst.src1)
|
||||
src = regs_.V(inst.src2);
|
||||
else if (inst.dest == inst.src2)
|
||||
if (inst.dest == inst.src1) {
|
||||
src = inst.src2;
|
||||
} else if (inst.dest == inst.src2) {
|
||||
imm = ~imm;
|
||||
else
|
||||
VOR_V(regs_.V(inst.dest), src, src);
|
||||
} else {
|
||||
VOR_V(regs_.V(inst.dest), regs_.V(src), regs_.V(src));
|
||||
src = inst.src2;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
if (imm & (1 << i)) {
|
||||
VEXTRINS_W(regs_.V(inst.dest), src, (i << 4) | i);
|
||||
}
|
||||
if (imm & (1 << i))
|
||||
VEXTRINS_W(regs_.V(inst.dest), regs_.V(src), (i << 4) | i);
|
||||
} else {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
int which = (inst.constant >> i) & 1;
|
||||
@@ -337,7 +338,7 @@ void LoongArch64JitBackend::CompIR_VecArith(IRInst inst) {
|
||||
case IROp::Vec4Abs:
|
||||
regs_.Map(inst);
|
||||
if (cpu_info.LOONGARCH_LSX)
|
||||
VBITSETI_W(regs_.V(inst.dest), regs_.V(inst.src1), 31);
|
||||
VBITCLRI_W(regs_.V(inst.dest), regs_.V(inst.src1), 31);
|
||||
else
|
||||
for (int i = 0; i < 4; ++i)
|
||||
FABS_S(regs_.F(inst.dest + i), regs_.F(inst.src1 + i));
|
||||
@@ -403,11 +404,11 @@ void LoongArch64JitBackend::CompIR_VecPack(IRInst inst) {
|
||||
|
||||
case IROp::Vec4Pack32To8:
|
||||
if (cpu_info.LOONGARCH_LSX) {
|
||||
regs_.Map(inst);
|
||||
if (Overlap(inst.dest, 1, inst.src1, 4))
|
||||
DISABLE;
|
||||
|
||||
VSRLI_W(EncodeRegToV(SCRATCHF1), regs_.V(inst.src1), 23);
|
||||
regs_.Map(inst);
|
||||
VSRLI_W(EncodeRegToV(SCRATCHF1), regs_.V(inst.src1), 24);
|
||||
VPICKEV_B(EncodeRegToV(SCRATCHF1), EncodeRegToV(SCRATCHF1), EncodeRegToV(SCRATCHF1));
|
||||
VPICKEV_B(regs_.V(inst.dest), EncodeRegToV(SCRATCHF1), EncodeRegToV(SCRATCHF1));
|
||||
} else {
|
||||
@@ -416,14 +417,16 @@ void LoongArch64JitBackend::CompIR_VecPack(IRInst inst) {
|
||||
break;
|
||||
|
||||
case IROp::Vec4Unpack8To32:
|
||||
regs_.Map(inst);
|
||||
if (cpu_info.LOONGARCH_LSX) {
|
||||
if (Overlap(inst.dest, 1, inst.src1, 4))
|
||||
DISABLE;
|
||||
|
||||
regs_.Map(inst);
|
||||
VSLLWIL_HU_BU(regs_.V(inst.dest), regs_.V(inst.src1), 0);
|
||||
VSLLWIL_WU_HU(regs_.V(inst.dest), regs_.V(inst.dest), 0);
|
||||
VSLLI_W(regs_.V(inst.dest), regs_.V(inst.dest), 24);
|
||||
} else {
|
||||
regs_.Map(inst);
|
||||
MOVFR2GR_S(SCRATCH2, regs_.F(inst.src1));
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
// Mask using walls.
|
||||
@@ -476,15 +479,16 @@ void LoongArch64JitBackend::CompIR_VecPack(IRInst inst) {
|
||||
|
||||
case IROp::Vec4Pack31To8:
|
||||
// TODO: This works for now, but may need to handle aliasing for vectors.
|
||||
regs_.Map(inst);
|
||||
if (cpu_info.LOONGARCH_LSX) {
|
||||
if (Overlap(inst.dest, 1, inst.src1, 4))
|
||||
DISABLE;
|
||||
|
||||
regs_.Map(inst);
|
||||
VSRLI_W(EncodeRegToV(SCRATCHF1), regs_.V(inst.src1), 23);
|
||||
VPICKEV_B(EncodeRegToV(SCRATCHF1), EncodeRegToV(SCRATCHF1), EncodeRegToV(SCRATCHF1));
|
||||
VPICKEV_B(regs_.V(inst.dest), EncodeRegToV(SCRATCHF1), EncodeRegToV(SCRATCHF1));
|
||||
}else {
|
||||
} else {
|
||||
regs_.Map(inst);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
MOVFR2GR_S(SCRATCH1, regs_.F(inst.src1 + i));
|
||||
SRLI_D(SCRATCH1, SCRATCH1, 23);
|
||||
|
||||
@@ -300,9 +300,7 @@ void LoongArch64RegCache::AdjustNativeRegAsPtr(IRNativeReg nreg, bool state) {
|
||||
}
|
||||
|
||||
bool LoongArch64RegCache::IsNativeRegCompatible(IRNativeReg nreg, MIPSLoc type, MIPSMap flags, int lanes) {
|
||||
// No special flags except VREG, skip the check for a little speed.
|
||||
if (type != MIPSLoc::VREG)
|
||||
return true;
|
||||
// No special flags, skip the check for a little speed.
|
||||
return IRNativeRegCacheBase::IsNativeRegCompatible(nreg, type, flags, lanes);
|
||||
}
|
||||
|
||||
|
||||
@@ -716,7 +716,7 @@ void VertexDecoderJitCache::Jit_Color4444Morph() {
|
||||
VILVL_B(reg, reg, reg);
|
||||
VAND_V(reg, reg, V8);
|
||||
VEXTRINS_W(lsxScratchReg3, reg, 0);
|
||||
VSLLI_H(fpScratchReg3, fpScratchReg3, 4);
|
||||
VSLLI_H(lsxScratchReg3, lsxScratchReg3, 4);
|
||||
VOR_V(reg, reg,lsxScratchReg3);
|
||||
VSRLI_W(reg, reg, 4);
|
||||
|
||||
@@ -781,7 +781,7 @@ void VertexDecoderJitCache::Jit_Color565Morph() {
|
||||
VFMUL_S(reg, reg, lsxScratchReg2);
|
||||
|
||||
if (!first) {
|
||||
VFADD_S(fpScratchReg, fpScratchReg, fpScratchReg3);
|
||||
VFADD_S(lsxScratchReg, lsxScratchReg, lsxScratchReg3);
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
@@ -833,7 +833,7 @@ void VertexDecoderJitCache::Jit_Color5551Morph() {
|
||||
VFMUL_S(reg, reg, lsxScratchReg2);
|
||||
|
||||
if (!first) {
|
||||
VFADD_S(fpScratchReg, fpScratchReg, fpScratchReg3);
|
||||
VFADD_S(lsxScratchReg, lsxScratchReg, lsxScratchReg3);
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
@@ -869,7 +869,7 @@ void VertexDecoderJitCache::Jit_TcU16ThroughToFloat() {
|
||||
LD_HU(tempReg2, srcReg, dec_->tcoff + 2);
|
||||
|
||||
auto updateSide = [&](LoongArch64Reg src, bool greater, LoongArch64Reg dst) {
|
||||
FixupBranch skip = BLT(greater ? dst : src, greater ? src : dst);
|
||||
FixupBranch skip = BLT(greater ? src : dst, greater ? dst : src);
|
||||
MOVE(dst, src);
|
||||
SetJumpTarget(skip);
|
||||
};
|
||||
@@ -879,8 +879,9 @@ void VertexDecoderJitCache::Jit_TcU16ThroughToFloat() {
|
||||
updateSide(tempReg2, false, boundsMinVReg);
|
||||
updateSide(tempReg2, true, boundsMaxVReg);
|
||||
|
||||
VINSGR2VR_W(lsxScratchReg, tempReg1, 0);
|
||||
VINSGR2VR_W(lsxScratchReg, tempReg2, 1);
|
||||
VINSGR2VR_H(lsxScratchReg, tempReg1, 0);
|
||||
VINSGR2VR_H(lsxScratchReg, tempReg2, 1);
|
||||
VSLLWIL_WU_HU(lsxScratchReg, lsxScratchReg, 0);
|
||||
VFFINT_S_WU(lsxScratchReg, lsxScratchReg);
|
||||
FST_D(fpSrc[0], dstReg, dec_->decFmt.uvoff);
|
||||
}
|
||||
|
||||
@@ -9771,13 +9771,17 @@ static const char *ir2_fpr_name[] = {
|
||||
"$ft8" , "$ft9" , "$ft10" , "$ft11" ,
|
||||
"$ft12" , "$ft13" , "$ft14" , "$ft15" ,
|
||||
"$fs0" , "$fs1" , "$fs2" , "$fs3" ,
|
||||
"$fs4" , "$fs5" , "$fs6" , "$s7" ,
|
||||
"$fs4" , "$fs5" , "$fs6" , "$fs7" ,
|
||||
};
|
||||
|
||||
static const char *ir2_scr_name[] = {
|
||||
"$scr0" , "$scr1" , "$scr2" , "$scr3",
|
||||
};
|
||||
|
||||
static const char *ir2_fcsr_name[] = {
|
||||
"$fcsr0" , "$fcsr1" , "$fcsr2" , "$fcsr3",
|
||||
};
|
||||
|
||||
static const char *ir2_cc_name[] = {
|
||||
"$cc0" , "$cc1" , "$cc2" , "$cc3" ,
|
||||
"$cc4" , "$cc5" , "$cc6" , "$cc7" ,
|
||||
@@ -9873,7 +9877,7 @@ void sprint_ins(Ins *ins, char * msg) {
|
||||
sprintf(msg + strlen(msg),"%s", ir2_fpr_name[ins->opnd[i].val]);
|
||||
break;
|
||||
case IR2_OPND_FCSR:
|
||||
sprintf(msg + strlen(msg),"%d", ins->opnd[i].val);
|
||||
sprintf(msg + strlen(msg),"%s", ir2_fcsr_name[ins->opnd[i].val]);
|
||||
break;
|
||||
case IR2_OPND_SCR:
|
||||
sprintf(msg + strlen(msg),"%s", ir2_scr_name[ins->opnd[i].val]);
|
||||
|
||||
Reference in new issue
Block a user