diff --git a/CMakeLists.txt b/CMakeLists.txt index 1778c9b734..5ae082f168 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1633,8 +1633,6 @@ list(APPEND CoreExtra Core/MIPS/RiscV/RiscVJit.h Core/MIPS/RiscV/RiscVRegCache.cpp Core/MIPS/RiscV/RiscVRegCache.h - Core/MIPS/RiscV/RiscVRegCacheFPU.cpp - Core/MIPS/RiscV/RiscVRegCacheFPU.h GPU/Common/VertexDecoderRiscV.cpp ) diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index b179805790..51ad7941a0 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -605,7 +605,6 @@ - @@ -1179,7 +1178,6 @@ - diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 627456ae70..190a475991 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -1216,9 +1216,6 @@ MIPS\RiscV - - MIPS\RiscV - MIPS\RiscV @@ -1998,9 +1995,6 @@ MIPS\RiscV - - MIPS\RiscV - MIPS\IR diff --git a/Core/MIPS/IR/IRRegCache.cpp b/Core/MIPS/IR/IRRegCache.cpp index 9f45e1e7b2..4ee289f6ac 100644 --- a/Core/MIPS/IR/IRRegCache.cpp +++ b/Core/MIPS/IR/IRRegCache.cpp @@ -563,12 +563,17 @@ void IRNativeRegCacheBase::FlushReg(IRReg mreg) { } } -void IRNativeRegCacheBase::FlushAll() { +void IRNativeRegCacheBase::FlushAll(bool gprs, bool fprs) { // Note: make sure not to change the registers when flushing. // Branching code may expect the native reg to retain its value. for (int i = 1; i < TOTAL_MAPPABLE_IRREGS; i++) { IRReg mipsReg = (IRReg)i; + if (!fprs && i >= 32 && IsValidFPR(mipsReg)) + continue; + if (!gprs && IsValidGPR(mipsReg)) + continue; + if (mr[i].isStatic) { IRNativeReg nreg = mr[i].nReg; // Cannot leave any IMMs in registers, not even MIPSLoc::REG_IMM. @@ -599,6 +604,10 @@ void IRNativeRegCacheBase::FlushAll() { int count = 0; const StaticAllocation *allocs = GetStaticAllocations(count); for (int i = 0; i < count; i++) { + if (!fprs && allocs[i].loc != MIPSLoc::FREG && allocs[i].loc != MIPSLoc::VREG) + continue; + if (!gprs && allocs[i].loc != MIPSLoc::REG) + continue; if (allocs[i].pointerified && !nr[allocs[i].nr].pointerified && jo_->enablePointerify) { // Re-pointerify if (mr[allocs[i].mr].loc == MIPSLoc::REG_IMM) diff --git a/Core/MIPS/IR/IRRegCache.h b/Core/MIPS/IR/IRRegCache.h index 7bc0460f6e..7b8a627773 100644 --- a/Core/MIPS/IR/IRRegCache.h +++ b/Core/MIPS/IR/IRRegCache.h @@ -184,7 +184,7 @@ public: void MarkGPRAsPointerDirty(IRReg gpr); virtual void Map(const IRInst &inst); - virtual void FlushAll(); + virtual void FlushAll(bool gprs = true, bool fprs = true); protected: virtual void SetupInitialRegs(); diff --git a/Core/MIPS/RiscV/RiscVAsm.cpp b/Core/MIPS/RiscV/RiscVAsm.cpp index a5205d7b9b..2bbd420f4f 100644 --- a/Core/MIPS/RiscV/RiscVAsm.cpp +++ b/Core/MIPS/RiscV/RiscVAsm.cpp @@ -51,11 +51,11 @@ void RiscVJitBackend::GenerateFixedCode(MIPSState *mipsState) { if (jo.useStaticAlloc) { saveStaticRegisters_ = AlignCode16(); SW(DOWNCOUNTREG, CTXREG, offsetof(MIPSState, downcount)); - gpr.EmitSaveStaticRegisters(); + regs_.EmitSaveStaticRegisters(); RET(); loadStaticRegisters_ = AlignCode16(); - gpr.EmitLoadStaticRegisters(); + regs_.EmitLoadStaticRegisters(); LW(DOWNCOUNTREG, CTXREG, offsetof(MIPSState, downcount)); RET(); diff --git a/Core/MIPS/RiscV/RiscVCompALU.cpp b/Core/MIPS/RiscV/RiscVCompALU.cpp index fbaf45c0af..eb0cc6dc79 100644 --- a/Core/MIPS/RiscV/RiscVCompALU.cpp +++ b/Core/MIPS/RiscV/RiscVCompALU.cpp @@ -53,47 +53,47 @@ void RiscVJitBackend::CompIR_Arith(IRInst inst) { switch (inst.op) { case IROp::Add: - gpr.Map(inst); - ADDW(gpr.R(inst.dest), gpr.R(inst.src1), gpr.R(inst.src2)); - gpr.MarkGPRDirty(inst.dest, true); + regs_.Map(inst); + ADDW(regs_.R(inst.dest), regs_.R(inst.src1), regs_.R(inst.src2)); + regs_.MarkGPRDirty(inst.dest, true); break; case IROp::Sub: - gpr.Map(inst); - SUBW(gpr.R(inst.dest), gpr.R(inst.src1), gpr.R(inst.src2)); - gpr.MarkGPRDirty(inst.dest, true); + regs_.Map(inst); + SUBW(regs_.R(inst.dest), regs_.R(inst.src1), regs_.R(inst.src2)); + regs_.MarkGPRDirty(inst.dest, true); break; case IROp::AddConst: if ((int32_t)inst.constant >= -2048 && (int32_t)inst.constant <= 2047) { // Typical of stack pointer updates. - if (gpr.IsGPRMappedAsPointer(inst.dest) && inst.dest == inst.src1 && allowPtrMath) { - gpr.MarkGPRAsPointerDirty(inst.dest); - ADDI(gpr.RPtr(inst.dest), gpr.RPtr(inst.dest), inst.constant); + if (regs_.IsGPRMappedAsPointer(inst.dest) && inst.dest == inst.src1 && allowPtrMath) { + regs_.MarkGPRAsPointerDirty(inst.dest); + ADDI(regs_.RPtr(inst.dest), regs_.RPtr(inst.dest), inst.constant); } else { - gpr.Map(inst); - ADDIW(gpr.R(inst.dest), gpr.R(inst.src1), inst.constant); - gpr.MarkGPRDirty(inst.dest, true); + regs_.Map(inst); + ADDIW(regs_.R(inst.dest), regs_.R(inst.src1), inst.constant); + regs_.MarkGPRDirty(inst.dest, true); } } else { - gpr.Map(inst); + regs_.Map(inst); LI(SCRATCH1, (int32_t)inst.constant); - ADDW(gpr.R(inst.dest), gpr.R(inst.src1), SCRATCH1); - gpr.MarkGPRDirty(inst.dest, true); + ADDW(regs_.R(inst.dest), regs_.R(inst.src1), SCRATCH1); + regs_.MarkGPRDirty(inst.dest, true); } break; case IROp::SubConst: - gpr.Map(inst); + regs_.Map(inst); LI(SCRATCH1, (int32_t)inst.constant); - SUBW(gpr.R(inst.dest), gpr.R(inst.src1), SCRATCH1); - gpr.MarkGPRDirty(inst.dest, true); + SUBW(regs_.R(inst.dest), regs_.R(inst.src1), SCRATCH1); + regs_.MarkGPRDirty(inst.dest, true); break; case IROp::Neg: - gpr.Map(inst); - SUBW(gpr.R(inst.dest), R_ZERO, gpr.R(inst.src1)); - gpr.MarkGPRDirty(inst.dest, true); + regs_.Map(inst); + SUBW(regs_.R(inst.dest), R_ZERO, regs_.R(inst.src1)); + regs_.MarkGPRDirty(inst.dest, true); break; default: @@ -109,81 +109,81 @@ void RiscVJitBackend::CompIR_Logic(IRInst inst) { switch (inst.op) { case IROp::And: if (inst.src1 != inst.src2) { - gpr.Map(inst); - AND(gpr.R(inst.dest), gpr.R(inst.src1), gpr.R(inst.src2)); + regs_.Map(inst); + AND(regs_.R(inst.dest), regs_.R(inst.src1), regs_.R(inst.src2)); } else if (inst.src1 != inst.dest) { - gpr.Map(inst); - MV(gpr.R(inst.dest), gpr.R(inst.src1)); - gpr.MarkGPRDirty(inst.dest, gpr.IsNormalized32(inst.src1)); + regs_.Map(inst); + MV(regs_.R(inst.dest), regs_.R(inst.src1)); + regs_.MarkGPRDirty(inst.dest, regs_.IsNormalized32(inst.src1)); } break; case IROp::Or: if (inst.src1 != inst.src2) { // If both were normalized before, the result is normalized. - resultNormalized = gpr.IsNormalized32(inst.src1) && gpr.IsNormalized32(inst.src2); - gpr.Map(inst); - OR(gpr.R(inst.dest), gpr.R(inst.src1), gpr.R(inst.src2)); - gpr.MarkGPRDirty(inst.dest, resultNormalized); + resultNormalized = regs_.IsNormalized32(inst.src1) && regs_.IsNormalized32(inst.src2); + regs_.Map(inst); + OR(regs_.R(inst.dest), regs_.R(inst.src1), regs_.R(inst.src2)); + regs_.MarkGPRDirty(inst.dest, resultNormalized); } else if (inst.src1 != inst.dest) { - gpr.Map(inst); - MV(gpr.R(inst.dest), gpr.R(inst.src1)); - gpr.MarkGPRDirty(inst.dest, gpr.IsNormalized32(inst.src1)); + regs_.Map(inst); + MV(regs_.R(inst.dest), regs_.R(inst.src1)); + regs_.MarkGPRDirty(inst.dest, regs_.IsNormalized32(inst.src1)); } break; case IROp::Xor: if (inst.src1 == inst.src2) { - gpr.SetGPRImm(inst.dest, 0); + regs_.SetGPRImm(inst.dest, 0); } else { - gpr.Map(inst); - XOR(gpr.R(inst.dest), gpr.R(inst.src1), gpr.R(inst.src2)); + regs_.Map(inst); + XOR(regs_.R(inst.dest), regs_.R(inst.src1), regs_.R(inst.src2)); } break; case IROp::AndConst: - resultNormalized = gpr.IsNormalized32(inst.src1); - gpr.Map(inst); + resultNormalized = regs_.IsNormalized32(inst.src1); + regs_.Map(inst); if ((int32_t)inst.constant >= -2048 && (int32_t)inst.constant <= 2047) { - ANDI(gpr.R(inst.dest), gpr.R(inst.src1), inst.constant); + ANDI(regs_.R(inst.dest), regs_.R(inst.src1), inst.constant); } else { LI(SCRATCH1, (int32_t)inst.constant); - AND(gpr.R(inst.dest), gpr.R(inst.src1), SCRATCH1); + AND(regs_.R(inst.dest), regs_.R(inst.src1), SCRATCH1); } // If the sign bits aren't cleared, and it was normalized before - it still is. if ((inst.constant & 0x80000000) != 0 && resultNormalized) - gpr.MarkGPRDirty(inst.dest, true); + regs_.MarkGPRDirty(inst.dest, true); // Otherwise, if we cleared the sign bits, it's naturally normalized. else if ((inst.constant & 0x80000000) == 0) - gpr.MarkGPRDirty(inst.dest, true); + regs_.MarkGPRDirty(inst.dest, true); break; case IROp::OrConst: - resultNormalized = gpr.IsNormalized32(inst.src1); - gpr.Map(inst); + resultNormalized = regs_.IsNormalized32(inst.src1); + regs_.Map(inst); if ((int32_t)inst.constant >= -2048 && (int32_t)inst.constant <= 2047) { - ORI(gpr.R(inst.dest), gpr.R(inst.src1), inst.constant); + ORI(regs_.R(inst.dest), regs_.R(inst.src1), inst.constant); } else { LI(SCRATCH1, (int32_t)inst.constant); - OR(gpr.R(inst.dest), gpr.R(inst.src1), SCRATCH1); + OR(regs_.R(inst.dest), regs_.R(inst.src1), SCRATCH1); } // Since our constant is normalized, oring its bits in won't hurt normalization. - gpr.MarkGPRDirty(inst.dest, resultNormalized); + regs_.MarkGPRDirty(inst.dest, resultNormalized); break; case IROp::XorConst: - gpr.Map(inst); + regs_.Map(inst); if ((int32_t)inst.constant >= -2048 && (int32_t)inst.constant <= 2047) { - XORI(gpr.R(inst.dest), gpr.R(inst.src1), inst.constant); + XORI(regs_.R(inst.dest), regs_.R(inst.src1), inst.constant); } else { LI(SCRATCH1, (int32_t)inst.constant); - XOR(gpr.R(inst.dest), gpr.R(inst.src1), SCRATCH1); + XOR(regs_.R(inst.dest), regs_.R(inst.src1), SCRATCH1); } break; case IROp::Not: - gpr.Map(inst); - NOT(gpr.R(inst.dest), gpr.R(inst.src1)); + regs_.Map(inst); + NOT(regs_.R(inst.dest), regs_.R(inst.src1)); break; default: @@ -198,32 +198,32 @@ void RiscVJitBackend::CompIR_Assign(IRInst inst) { switch (inst.op) { case IROp::Mov: if (inst.dest != inst.src1) { - gpr.Map(inst); - MV(gpr.R(inst.dest), gpr.R(inst.src1)); - gpr.MarkGPRDirty(inst.dest, gpr.IsNormalized32(inst.src1)); + regs_.Map(inst); + MV(regs_.R(inst.dest), regs_.R(inst.src1)); + regs_.MarkGPRDirty(inst.dest, regs_.IsNormalized32(inst.src1)); } break; case IROp::Ext8to32: - gpr.Map(inst); + regs_.Map(inst); if (cpu_info.RiscV_Zbb) { - SEXT_B(gpr.R(inst.dest), gpr.R(inst.src1)); + SEXT_B(regs_.R(inst.dest), regs_.R(inst.src1)); } else { - SLLI(gpr.R(inst.dest), gpr.R(inst.src1), 24); - SRAIW(gpr.R(inst.dest), gpr.R(inst.dest), 24); + SLLI(regs_.R(inst.dest), regs_.R(inst.src1), 24); + SRAIW(regs_.R(inst.dest), regs_.R(inst.dest), 24); } - gpr.MarkGPRDirty(inst.dest, true); + regs_.MarkGPRDirty(inst.dest, true); break; case IROp::Ext16to32: - gpr.Map(inst); + regs_.Map(inst); if (cpu_info.RiscV_Zbb) { - SEXT_H(gpr.R(inst.dest), gpr.R(inst.src1)); + SEXT_H(regs_.R(inst.dest), regs_.R(inst.src1)); } else { - SLLI(gpr.R(inst.dest), gpr.R(inst.src1), 16); - SRAIW(gpr.R(inst.dest), gpr.R(inst.dest), 16); + SLLI(regs_.R(inst.dest), regs_.R(inst.src1), 16); + SRAIW(regs_.R(inst.dest), regs_.R(inst.dest), 16); } - gpr.MarkGPRDirty(inst.dest, true); + regs_.MarkGPRDirty(inst.dest, true); break; default: @@ -238,37 +238,37 @@ void RiscVJitBackend::CompIR_Bits(IRInst inst) { switch (inst.op) { case IROp::ReverseBits: if (cpu_info.RiscV_Zbb) { - gpr.Map(inst); + regs_.Map(inst); // Start by reversing bytes (note: this puts in upper 32 of XLEN.) - REV8(gpr.R(inst.dest), gpr.R(inst.src1)); + REV8(regs_.R(inst.dest), regs_.R(inst.src1)); // Swap nibbles. LI(SCRATCH1, (s32)0xF0F0F0F0); - SRLI(SCRATCH2, gpr.R(inst.dest), XLEN - 32 - 4); + SRLI(SCRATCH2, regs_.R(inst.dest), XLEN - 32 - 4); AND(SCRATCH2, SCRATCH2, SCRATCH1); if (XLEN >= 64) - SRLI(gpr.R(inst.dest), gpr.R(inst.dest), XLEN - 28); + SRLI(regs_.R(inst.dest), regs_.R(inst.dest), XLEN - 28); else - SLLI(gpr.R(inst.dest), gpr.R(inst.dest), 4); + SLLI(regs_.R(inst.dest), regs_.R(inst.dest), 4); SRLIW(SCRATCH1, SCRATCH1, 4); - AND(gpr.R(inst.dest), gpr.R(inst.dest), SCRATCH1); - OR(gpr.R(inst.dest), gpr.R(inst.dest), SCRATCH2); + AND(regs_.R(inst.dest), regs_.R(inst.dest), SCRATCH1); + OR(regs_.R(inst.dest), regs_.R(inst.dest), SCRATCH2); // Now the consecutive pairs. LI(SCRATCH1, (s32)0x33333333); - SRLI(SCRATCH2, gpr.R(inst.dest), 2); + SRLI(SCRATCH2, regs_.R(inst.dest), 2); AND(SCRATCH2, SCRATCH2, SCRATCH1); - AND(gpr.R(inst.dest), gpr.R(inst.dest), SCRATCH1); - SLLIW(gpr.R(inst.dest), gpr.R(inst.dest), 2); - OR(gpr.R(inst.dest), gpr.R(inst.dest), SCRATCH2); + AND(regs_.R(inst.dest), regs_.R(inst.dest), SCRATCH1); + SLLIW(regs_.R(inst.dest), regs_.R(inst.dest), 2); + OR(regs_.R(inst.dest), regs_.R(inst.dest), SCRATCH2); // And finally the even and odd bits. LI(SCRATCH1, (s32)0x55555555); - SRLI(SCRATCH2, gpr.R(inst.dest), 1); + SRLI(SCRATCH2, regs_.R(inst.dest), 1); AND(SCRATCH2, SCRATCH2, SCRATCH1); - AND(gpr.R(inst.dest), gpr.R(inst.dest), SCRATCH1); - SLLIW(gpr.R(inst.dest), gpr.R(inst.dest), 1); - OR(gpr.R(inst.dest), gpr.R(inst.dest), SCRATCH2); + AND(regs_.R(inst.dest), regs_.R(inst.dest), SCRATCH1); + SLLIW(regs_.R(inst.dest), regs_.R(inst.dest), 1); + OR(regs_.R(inst.dest), regs_.R(inst.dest), SCRATCH2); } else { CompIR_Generic(inst); } @@ -280,12 +280,12 @@ void RiscVJitBackend::CompIR_Bits(IRInst inst) { case IROp::BSwap32: if (cpu_info.RiscV_Zbb) { - gpr.Map(inst); - REV8(gpr.R(inst.dest), gpr.R(inst.src1)); + regs_.Map(inst); + REV8(regs_.R(inst.dest), regs_.R(inst.src1)); if (XLEN >= 64) { // REV8 swaps the entire register, so get the 32 highest bits. - SRAI(gpr.R(inst.dest), gpr.R(inst.dest), XLEN - 32); - gpr.MarkGPRDirty(inst.dest, true); + SRAI(regs_.R(inst.dest), regs_.R(inst.dest), XLEN - 32); + regs_.MarkGPRDirty(inst.dest, true); } } else { CompIR_Generic(inst); @@ -294,10 +294,10 @@ void RiscVJitBackend::CompIR_Bits(IRInst inst) { case IROp::Clz: if (cpu_info.RiscV_Zbb) { - gpr.Map(inst); + regs_.Map(inst); // This even sets to 32 when zero, perfect. - CLZW(gpr.R(inst.dest), gpr.R(inst.src1)); - gpr.MarkGPRDirty(inst.dest, true); + CLZW(regs_.R(inst.dest), regs_.R(inst.src1)); + regs_.MarkGPRDirty(inst.dest, true); } else { CompIR_Generic(inst); } @@ -314,28 +314,28 @@ void RiscVJitBackend::CompIR_Shift(IRInst inst) { switch (inst.op) { case IROp::Shl: - gpr.Map(inst); - SLLW(gpr.R(inst.dest), gpr.R(inst.src1), gpr.R(inst.src2)); - gpr.MarkGPRDirty(inst.dest, true); + regs_.Map(inst); + SLLW(regs_.R(inst.dest), regs_.R(inst.src1), regs_.R(inst.src2)); + regs_.MarkGPRDirty(inst.dest, true); break; case IROp::Shr: - gpr.Map(inst); - SRLW(gpr.R(inst.dest), gpr.R(inst.src1), gpr.R(inst.src2)); - gpr.MarkGPRDirty(inst.dest, true); + regs_.Map(inst); + SRLW(regs_.R(inst.dest), regs_.R(inst.src1), regs_.R(inst.src2)); + regs_.MarkGPRDirty(inst.dest, true); break; case IROp::Sar: - gpr.Map(inst); - SRAW(gpr.R(inst.dest), gpr.R(inst.src1), gpr.R(inst.src2)); - gpr.MarkGPRDirty(inst.dest, true); + regs_.Map(inst); + SRAW(regs_.R(inst.dest), regs_.R(inst.src1), regs_.R(inst.src2)); + regs_.MarkGPRDirty(inst.dest, true); break; case IROp::Ror: if (cpu_info.RiscV_Zbb) { - gpr.Map(inst); - RORW(gpr.R(inst.dest), gpr.R(inst.src1), gpr.R(inst.src2)); - gpr.MarkGPRDirty(inst.dest, true); + regs_.Map(inst); + RORW(regs_.R(inst.dest), regs_.R(inst.src1), regs_.R(inst.src2)); + regs_.MarkGPRDirty(inst.dest, true); } else { CompIR_Generic(inst); } @@ -344,67 +344,67 @@ void RiscVJitBackend::CompIR_Shift(IRInst inst) { case IROp::ShlImm: // Shouldn't happen, but let's be safe of any passes that modify the ops. if (inst.src2 >= 32) { - gpr.SetGPRImm(inst.dest, 0); + regs_.SetGPRImm(inst.dest, 0); } else if (inst.src2 == 0) { if (inst.dest != inst.src1) { - gpr.Map(inst); - MV(gpr.R(inst.dest), gpr.R(inst.src1)); - gpr.MarkGPRDirty(inst.dest, gpr.IsNormalized32(inst.src1)); + regs_.Map(inst); + MV(regs_.R(inst.dest), regs_.R(inst.src1)); + regs_.MarkGPRDirty(inst.dest, regs_.IsNormalized32(inst.src1)); } } else { - gpr.Map(inst); - SLLIW(gpr.R(inst.dest), gpr.R(inst.src1), inst.src2); - gpr.MarkGPRDirty(inst.dest, true); + regs_.Map(inst); + SLLIW(regs_.R(inst.dest), regs_.R(inst.src1), inst.src2); + regs_.MarkGPRDirty(inst.dest, true); } break; case IROp::ShrImm: // Shouldn't happen, but let's be safe of any passes that modify the ops. if (inst.src2 >= 32) { - gpr.SetGPRImm(inst.dest, 0); + regs_.SetGPRImm(inst.dest, 0); } else if (inst.src2 == 0) { if (inst.dest != inst.src1) { - gpr.Map(inst); - MV(gpr.R(inst.dest), gpr.R(inst.src1)); - gpr.MarkGPRDirty(inst.dest, gpr.IsNormalized32(inst.src1)); + regs_.Map(inst); + MV(regs_.R(inst.dest), regs_.R(inst.src1)); + regs_.MarkGPRDirty(inst.dest, regs_.IsNormalized32(inst.src1)); } } else { - gpr.Map(inst); - SRLIW(gpr.R(inst.dest), gpr.R(inst.src1), inst.src2); - gpr.MarkGPRDirty(inst.dest, true); + regs_.Map(inst); + SRLIW(regs_.R(inst.dest), regs_.R(inst.src1), inst.src2); + regs_.MarkGPRDirty(inst.dest, true); } break; case IROp::SarImm: // Shouldn't happen, but let's be safe of any passes that modify the ops. if (inst.src2 >= 32) { - gpr.Map(inst); - SRAIW(gpr.R(inst.dest), gpr.R(inst.src1), 31); - gpr.MarkGPRDirty(inst.dest, true); + regs_.Map(inst); + SRAIW(regs_.R(inst.dest), regs_.R(inst.src1), 31); + regs_.MarkGPRDirty(inst.dest, true); } else if (inst.src2 == 0) { if (inst.dest != inst.src1) { - gpr.Map(inst); - MV(gpr.R(inst.dest), gpr.R(inst.src1)); - gpr.MarkGPRDirty(inst.dest, gpr.IsNormalized32(inst.src1)); + regs_.Map(inst); + MV(regs_.R(inst.dest), regs_.R(inst.src1)); + regs_.MarkGPRDirty(inst.dest, regs_.IsNormalized32(inst.src1)); } } else { - gpr.Map(inst); - SRAIW(gpr.R(inst.dest), gpr.R(inst.src1), inst.src2); - gpr.MarkGPRDirty(inst.dest, true); + regs_.Map(inst); + SRAIW(regs_.R(inst.dest), regs_.R(inst.src1), inst.src2); + regs_.MarkGPRDirty(inst.dest, true); } break; case IROp::RorImm: if (inst.src2 == 0) { if (inst.dest != inst.src1) { - gpr.Map(inst); - MV(gpr.R(inst.dest), gpr.R(inst.src1)); - gpr.MarkGPRDirty(inst.dest, gpr.IsNormalized32(inst.src1)); + regs_.Map(inst); + MV(regs_.R(inst.dest), regs_.R(inst.src1)); + regs_.MarkGPRDirty(inst.dest, regs_.IsNormalized32(inst.src1)); } } else if (cpu_info.RiscV_Zbb) { - gpr.Map(inst); - RORIW(gpr.R(inst.dest), gpr.R(inst.src1), inst.src2 & 31); - gpr.MarkGPRDirty(inst.dest, true); + regs_.Map(inst); + RORIW(regs_.R(inst.dest), regs_.R(inst.src1), inst.src2 & 31); + regs_.MarkGPRDirty(inst.dest, true); } else { CompIR_Generic(inst); } @@ -423,58 +423,58 @@ void RiscVJitBackend::CompIR_Compare(IRInst inst) { RiscVReg rhs = INVALID_REG; switch (inst.op) { case IROp::Slt: - gpr.Map(inst); + regs_.Map(inst); NormalizeSrc12(inst, &lhs, &rhs, SCRATCH1, SCRATCH2, true); - SLT(gpr.R(inst.dest), lhs, rhs); - gpr.MarkGPRDirty(inst.dest, true); + SLT(regs_.R(inst.dest), lhs, rhs); + regs_.MarkGPRDirty(inst.dest, true); break; case IROp::SltConst: if (inst.constant == 0) { // Basically, getting the sign bit. Let's shift instead. - gpr.Map(inst); - SRLIW(gpr.R(inst.dest), gpr.R(inst.src1), 31); - gpr.MarkGPRDirty(inst.dest, true); + regs_.Map(inst); + SRLIW(regs_.R(inst.dest), regs_.R(inst.src1), 31); + regs_.MarkGPRDirty(inst.dest, true); } else { - gpr.Map(inst); + regs_.Map(inst); NormalizeSrc1(inst, &lhs, SCRATCH1, false); if ((int32_t)inst.constant >= -2048 && (int32_t)inst.constant <= 2047) { - SLTI(gpr.R(inst.dest), lhs, (int32_t)inst.constant); + SLTI(regs_.R(inst.dest), lhs, (int32_t)inst.constant); } else { LI(SCRATCH2, (int32_t)inst.constant); - SLT(gpr.R(inst.dest), lhs, SCRATCH2); + SLT(regs_.R(inst.dest), lhs, SCRATCH2); } - gpr.MarkGPRDirty(inst.dest, true); + regs_.MarkGPRDirty(inst.dest, true); } break; case IROp::SltU: - gpr.Map(inst); + regs_.Map(inst); // It's still fine to sign extend, the biggest just get even bigger. NormalizeSrc12(inst, &lhs, &rhs, SCRATCH1, SCRATCH2, true); - SLTU(gpr.R(inst.dest), lhs, rhs); - gpr.MarkGPRDirty(inst.dest, true); + SLTU(regs_.R(inst.dest), lhs, rhs); + regs_.MarkGPRDirty(inst.dest, true); break; case IROp::SltUConst: if (inst.constant == 0) { - gpr.SetGPRImm(inst.dest, 0); + regs_.SetGPRImm(inst.dest, 0); } else { - gpr.Map(inst); + regs_.Map(inst); NormalizeSrc1(inst, &lhs, SCRATCH1, false); // We sign extend because we're comparing against something normalized. // It's also the most efficient to set. if ((int32_t)inst.constant >= -2048 && (int32_t)inst.constant <= 2047) { - SLTIU(gpr.R(inst.dest), lhs, (int32_t)inst.constant); + SLTIU(regs_.R(inst.dest), lhs, (int32_t)inst.constant); } else { LI(SCRATCH2, (int32_t)inst.constant); - SLTU(gpr.R(inst.dest), lhs, SCRATCH2); + SLTU(regs_.R(inst.dest), lhs, SCRATCH2); } - gpr.MarkGPRDirty(inst.dest, true); + regs_.MarkGPRDirty(inst.dest, true); } break; @@ -497,7 +497,7 @@ void RiscVJitBackend::CompIR_CondAssign(IRInst inst) { return; // We could have a "zero" with wrong upper due to XOR, so we have to normalize. - gpr.Map(inst); + regs_.Map(inst); NormalizeSrc1(inst, &lhs, SCRATCH1, true); switch (inst.op) { @@ -512,43 +512,43 @@ void RiscVJitBackend::CompIR_CondAssign(IRInst inst) { break; } - MV(gpr.R(inst.dest), gpr.R(inst.src2)); + MV(regs_.R(inst.dest), regs_.R(inst.src2)); SetJumpTarget(fixup); break; case IROp::Max: if (inst.src1 != inst.src2) { if (cpu_info.RiscV_Zbb) { - gpr.Map(inst); + regs_.Map(inst); NormalizeSrc12(inst, &lhs, &rhs, SCRATCH1, SCRATCH2, true); - MAX(gpr.R(inst.dest), lhs, rhs); + MAX(regs_.R(inst.dest), lhs, rhs); // Because we had to normalize the inputs, the output is normalized. - gpr.MarkGPRDirty(inst.dest, true); + regs_.MarkGPRDirty(inst.dest, true); } else { CompIR_Generic(inst); } } else if (inst.dest != inst.src1) { - gpr.Map(inst); - MV(gpr.R(inst.dest), gpr.R(inst.src1)); - gpr.MarkGPRDirty(inst.dest, gpr.IsNormalized32(inst.src1)); + regs_.Map(inst); + MV(regs_.R(inst.dest), regs_.R(inst.src1)); + regs_.MarkGPRDirty(inst.dest, regs_.IsNormalized32(inst.src1)); } break; case IROp::Min: if (inst.src1 != inst.src2) { if (cpu_info.RiscV_Zbb) { - gpr.Map(inst); + regs_.Map(inst); NormalizeSrc12(inst, &lhs, &rhs, SCRATCH1, SCRATCH2, true); - MIN(gpr.R(inst.dest), lhs, rhs); + MIN(regs_.R(inst.dest), lhs, rhs); // Because we had to normalize the inputs, the output is normalized. - gpr.MarkGPRDirty(inst.dest, true); + regs_.MarkGPRDirty(inst.dest, true); } else { CompIR_Generic(inst); } } else if (inst.dest != inst.src1) { - gpr.Map(inst); - MV(gpr.R(inst.dest), gpr.R(inst.src1)); - gpr.MarkGPRDirty(inst.dest, gpr.IsNormalized32(inst.src1)); + regs_.Map(inst); + MV(regs_.R(inst.dest), regs_.R(inst.src1)); + regs_.MarkGPRDirty(inst.dest, regs_.IsNormalized32(inst.src1)); } break; @@ -563,27 +563,27 @@ void RiscVJitBackend::CompIR_HiLo(IRInst inst) { switch (inst.op) { case IROp::MtLo: - gpr.MapDirtyIn(IRREG_LO, inst.src1); - MV(gpr.R(IRREG_LO), gpr.R(inst.src1)); - gpr.MarkGPRDirty(IRREG_LO, gpr.IsNormalized32(inst.src1)); + regs_.MapGPRDirtyIn(IRREG_LO, inst.src1); + MV(regs_.R(IRREG_LO), regs_.R(inst.src1)); + regs_.MarkGPRDirty(IRREG_LO, regs_.IsNormalized32(inst.src1)); break; case IROp::MtHi: - gpr.MapDirtyIn(IRREG_HI, inst.src1); - MV(gpr.R(IRREG_HI), gpr.R(inst.src1)); - gpr.MarkGPRDirty(IRREG_HI, gpr.IsNormalized32(inst.src1)); + regs_.MapGPRDirtyIn(IRREG_HI, inst.src1); + MV(regs_.R(IRREG_HI), regs_.R(inst.src1)); + regs_.MarkGPRDirty(IRREG_HI, regs_.IsNormalized32(inst.src1)); break; case IROp::MfLo: - gpr.MapDirtyIn(inst.dest, IRREG_LO); - MV(gpr.R(inst.dest), gpr.R(IRREG_LO)); - gpr.MarkGPRDirty(inst.dest, gpr.IsNormalized32(IRREG_LO)); + regs_.MapGPRDirtyIn(inst.dest, IRREG_LO); + MV(regs_.R(inst.dest), regs_.R(IRREG_LO)); + regs_.MarkGPRDirty(inst.dest, regs_.IsNormalized32(IRREG_LO)); break; case IROp::MfHi: - gpr.MapDirtyIn(inst.dest, IRREG_HI); - MV(gpr.R(inst.dest), gpr.R(IRREG_HI)); - gpr.MarkGPRDirty(inst.dest, gpr.IsNormalized32(IRREG_HI)); + regs_.MapGPRDirtyIn(inst.dest, IRREG_HI); + MV(regs_.R(inst.dest), regs_.R(IRREG_HI)); + regs_.MarkGPRDirty(inst.dest, regs_.IsNormalized32(IRREG_HI)); break; default: @@ -597,12 +597,12 @@ void RiscVJitBackend::CompIR_Mult(IRInst inst) { auto makeArgsUnsigned = [&](RiscVReg *lhs, RiscVReg *rhs) { if (cpu_info.RiscV_Zba) { - ZEXT_W(SCRATCH1, gpr.R(inst.src1)); - ZEXT_W(SCRATCH2, gpr.R(inst.src2)); + ZEXT_W(SCRATCH1, regs_.R(inst.src1)); + ZEXT_W(SCRATCH2, regs_.R(inst.src2)); } else { - SLLI(SCRATCH1, gpr.R(inst.src1), XLEN - 32); + SLLI(SCRATCH1, regs_.R(inst.src1), XLEN - 32); SRLI(SCRATCH1, SCRATCH1, XLEN - 32); - SLLI(SCRATCH2, gpr.R(inst.src2), XLEN - 32); + SLLI(SCRATCH2, regs_.R(inst.src2), XLEN - 32); SRLI(SCRATCH2, SCRATCH2, XLEN - 32); } *lhs = SCRATCH1; @@ -611,17 +611,17 @@ void RiscVJitBackend::CompIR_Mult(IRInst inst) { auto combinePrevMulResult = [&] { // TODO: Using a single reg for HI/LO would make this less ugly. if (cpu_info.RiscV_Zba) { - ZEXT_W(gpr.R(IRREG_LO), gpr.R(IRREG_LO)); + ZEXT_W(regs_.R(IRREG_LO), regs_.R(IRREG_LO)); } else { - SLLI(gpr.R(IRREG_LO), gpr.R(IRREG_LO), XLEN - 32); - SRLI(gpr.R(IRREG_LO), gpr.R(IRREG_LO), XLEN - 32); + SLLI(regs_.R(IRREG_LO), regs_.R(IRREG_LO), XLEN - 32); + SRLI(regs_.R(IRREG_LO), regs_.R(IRREG_LO), XLEN - 32); } - SLLI(gpr.R(IRREG_HI), gpr.R(IRREG_HI), 32); - OR(gpr.R(IRREG_LO), gpr.R(IRREG_LO), gpr.R(IRREG_HI)); + SLLI(regs_.R(IRREG_HI), regs_.R(IRREG_HI), 32); + OR(regs_.R(IRREG_LO), regs_.R(IRREG_LO), regs_.R(IRREG_HI)); }; auto splitMulResult = [&] { - SRAI(gpr.R(IRREG_HI), gpr.R(IRREG_LO), 32); - gpr.MarkGPRDirty(IRREG_HI, true); + SRAI(regs_.R(IRREG_HI), regs_.R(IRREG_LO), 32); + regs_.MarkGPRDirty(IRREG_HI, true); }; RiscVReg lhs = INVALID_REG; @@ -630,58 +630,58 @@ void RiscVJitBackend::CompIR_Mult(IRInst inst) { case IROp::Mult: // TODO: Maybe IR could simplify when HI is not needed or clobbered? // TODO: HI/LO merge optimization? Have to be careful of passes that split them... - gpr.MapDirtyDirtyInIn(IRREG_LO, IRREG_HI, inst.src1, inst.src2); + regs_.MapGPRDirtyDirtyInIn(IRREG_LO, IRREG_HI, inst.src1, inst.src2); NormalizeSrc12(inst, &lhs, &rhs, SCRATCH1, SCRATCH2, true); - MUL(gpr.R(IRREG_LO), lhs, rhs); + MUL(regs_.R(IRREG_LO), lhs, rhs); splitMulResult(); break; case IROp::MultU: // This is an "anti-norm32" case. Let's just zero always. // TODO: If we could know that LO was only needed, we could use MULW and be done. - gpr.MapDirtyDirtyInIn(IRREG_LO, IRREG_HI, inst.src1, inst.src2); + regs_.MapGPRDirtyDirtyInIn(IRREG_LO, IRREG_HI, inst.src1, inst.src2); makeArgsUnsigned(&lhs, &rhs); - MUL(gpr.R(IRREG_LO), lhs, rhs); + MUL(regs_.R(IRREG_LO), lhs, rhs); splitMulResult(); break; case IROp::Madd: - gpr.MapDirtyDirtyInIn(IRREG_LO, IRREG_HI, inst.src1, inst.src2, MapType::ALWAYS_LOAD); + regs_.MapGPRDirtyDirtyInIn(IRREG_LO, IRREG_HI, inst.src1, inst.src2, MapType::ALWAYS_LOAD); NormalizeSrc12(inst, &lhs, &rhs, SCRATCH1, SCRATCH2, true); MUL(SCRATCH1, lhs, rhs); combinePrevMulResult(); - ADD(gpr.R(IRREG_LO), gpr.R(IRREG_LO), SCRATCH1); + ADD(regs_.R(IRREG_LO), regs_.R(IRREG_LO), SCRATCH1); splitMulResult(); break; case IROp::MaddU: - gpr.MapDirtyDirtyInIn(IRREG_LO, IRREG_HI, inst.src1, inst.src2, MapType::ALWAYS_LOAD); + regs_.MapGPRDirtyDirtyInIn(IRREG_LO, IRREG_HI, inst.src1, inst.src2, MapType::ALWAYS_LOAD); makeArgsUnsigned(&lhs, &rhs); MUL(SCRATCH1, lhs, rhs); combinePrevMulResult(); - ADD(gpr.R(IRREG_LO), gpr.R(IRREG_LO), SCRATCH1); + ADD(regs_.R(IRREG_LO), regs_.R(IRREG_LO), SCRATCH1); splitMulResult(); break; case IROp::Msub: - gpr.MapDirtyDirtyInIn(IRREG_LO, IRREG_HI, inst.src1, inst.src2, MapType::ALWAYS_LOAD); + regs_.MapGPRDirtyDirtyInIn(IRREG_LO, IRREG_HI, inst.src1, inst.src2, MapType::ALWAYS_LOAD); NormalizeSrc12(inst, &lhs, &rhs, SCRATCH1, SCRATCH2, true); MUL(SCRATCH1, lhs, rhs); combinePrevMulResult(); - SUB(gpr.R(IRREG_LO), gpr.R(IRREG_LO), SCRATCH1); + SUB(regs_.R(IRREG_LO), regs_.R(IRREG_LO), SCRATCH1); splitMulResult(); break; case IROp::MsubU: - gpr.MapDirtyDirtyInIn(IRREG_LO, IRREG_HI, inst.src1, inst.src2, MapType::ALWAYS_LOAD); + regs_.MapGPRDirtyDirtyInIn(IRREG_LO, IRREG_HI, inst.src1, inst.src2, MapType::ALWAYS_LOAD); makeArgsUnsigned(&lhs, &rhs); MUL(SCRATCH1, lhs, rhs); combinePrevMulResult(); - SUB(gpr.R(IRREG_LO), gpr.R(IRREG_LO), SCRATCH1); + SUB(regs_.R(IRREG_LO), regs_.R(IRREG_LO), SCRATCH1); splitMulResult(); break; @@ -697,18 +697,18 @@ void RiscVJitBackend::CompIR_Div(IRInst inst) { RiscVReg numReg, denomReg; switch (inst.op) { case IROp::Div: - gpr.MapDirtyDirtyInIn(IRREG_LO, IRREG_HI, inst.src1, inst.src2, MapType::AVOID_LOAD_MARK_NORM32); + regs_.MapGPRDirtyDirtyInIn(IRREG_LO, IRREG_HI, inst.src1, inst.src2, MapType::AVOID_LOAD_MARK_NORM32); // We have to do this because of the divide by zero and overflow checks below. NormalizeSrc12(inst, &numReg, &denomReg, SCRATCH1, SCRATCH2, true); - DIVW(gpr.R(IRREG_LO), numReg, denomReg); - REMW(gpr.R(IRREG_HI), numReg, denomReg); + DIVW(regs_.R(IRREG_LO), numReg, denomReg); + REMW(regs_.R(IRREG_HI), numReg, denomReg); // Now some tweaks for divide by zero and overflow. { // Start with divide by zero, remainder is fine. FixupBranch skipNonZero = BNE(denomReg, R_ZERO); FixupBranch keepNegOne = BGE(numReg, R_ZERO); - LI(gpr.R(IRREG_LO), 1); + LI(regs_.R(IRREG_LO), 1); SetJumpTarget(keepNegOne); SetJumpTarget(skipNonZero); @@ -718,18 +718,18 @@ void RiscVJitBackend::CompIR_Div(IRInst inst) { FixupBranch notMostNegative = BNE(numReg, R_RA); LI(R_RA, -1); FixupBranch notNegativeOne = BNE(denomReg, R_RA); - LI(gpr.R(IRREG_HI), -1); + LI(regs_.R(IRREG_HI), -1); SetJumpTarget(notNegativeOne); SetJumpTarget(notMostNegative); } break; case IROp::DivU: - gpr.MapDirtyDirtyInIn(IRREG_LO, IRREG_HI, inst.src1, inst.src2, MapType::AVOID_LOAD_MARK_NORM32); + regs_.MapGPRDirtyDirtyInIn(IRREG_LO, IRREG_HI, inst.src1, inst.src2, MapType::AVOID_LOAD_MARK_NORM32); // We have to do this because of the divide by zero check below. NormalizeSrc12(inst, &numReg, &denomReg, SCRATCH1, SCRATCH2, true); - DIVUW(gpr.R(IRREG_LO), numReg, denomReg); - REMUW(gpr.R(IRREG_HI), numReg, denomReg); + DIVUW(regs_.R(IRREG_LO), numReg, denomReg); + REMUW(regs_.R(IRREG_HI), numReg, denomReg); // On divide by zero, everything is correct already except the 0xFFFF case. { @@ -737,7 +737,7 @@ void RiscVJitBackend::CompIR_Div(IRInst inst) { // Luckily, we don't need SCRATCH2/denomReg anymore. LI(SCRATCH2, 0xFFFF); FixupBranch keepNegOne = BLTU(SCRATCH2, numReg); - MV(gpr.R(IRREG_LO), SCRATCH2); + MV(regs_.R(IRREG_LO), SCRATCH2); SetJumpTarget(keepNegOne); SetJumpTarget(skipNonZero); } diff --git a/Core/MIPS/RiscV/RiscVCompBranch.cpp b/Core/MIPS/RiscV/RiscVCompBranch.cpp index f146fdd1ee..f1126b0317 100644 --- a/Core/MIPS/RiscV/RiscVCompBranch.cpp +++ b/Core/MIPS/RiscV/RiscVCompBranch.cpp @@ -45,7 +45,7 @@ void RiscVJitBackend::CompIR_Exit(IRInst inst) { break; case IROp::ExitToReg: - exitReg = gpr.MapGPR(inst.src1); + exitReg = regs_.MapGPR(inst.src1); FlushAll(); // TODO: If ever we don't read this back in dispatcherPCInSCRATCH1_, we should zero upper. MV(SCRATCH1, exitReg); @@ -72,7 +72,7 @@ void RiscVJitBackend::CompIR_ExitIf(IRInst inst) { switch (inst.op) { case IROp::ExitToConstIfEq: case IROp::ExitToConstIfNeq: - gpr.Map(inst); + regs_.Map(inst); // We can't use SCRATCH1, which is destroyed by FlushAll()... but cheat and use R_RA. NormalizeSrc12(inst, &lhs, &rhs, R_RA, SCRATCH2, true); FlushAll(); @@ -99,7 +99,7 @@ void RiscVJitBackend::CompIR_ExitIf(IRInst inst) { case IROp::ExitToConstIfGeZ: case IROp::ExitToConstIfLtZ: case IROp::ExitToConstIfLeZ: - gpr.Map(inst); + regs_.Map(inst); NormalizeSrc1(inst, &lhs, SCRATCH2, true); FlushAll(); diff --git a/Core/MIPS/RiscV/RiscVCompFPU.cpp b/Core/MIPS/RiscV/RiscVCompFPU.cpp index 5e668ce907..bdc2def130 100644 --- a/Core/MIPS/RiscV/RiscVCompFPU.cpp +++ b/Core/MIPS/RiscV/RiscVCompFPU.cpp @@ -39,35 +39,35 @@ void RiscVJitBackend::CompIR_FArith(IRInst inst) { switch (inst.op) { case IROp::FAdd: - fpr.Map(inst); - FADD(32, fpr.R(inst.dest), fpr.R(inst.src1), fpr.R(inst.src2)); + regs_.Map(inst); + FADD(32, regs_.F(inst.dest), regs_.F(inst.src1), regs_.F(inst.src2)); break; case IROp::FSub: - fpr.Map(inst); - FSUB(32, fpr.R(inst.dest), fpr.R(inst.src1), fpr.R(inst.src2)); + regs_.Map(inst); + FSUB(32, regs_.F(inst.dest), regs_.F(inst.src1), regs_.F(inst.src2)); break; case IROp::FMul: - fpr.Map(inst); + regs_.Map(inst); // We'll assume everyone will make it such that 0 * infinity = NAN properly. // See blame on this comment if that proves untrue. - FMUL(32, fpr.R(inst.dest), fpr.R(inst.src1), fpr.R(inst.src2)); + FMUL(32, regs_.F(inst.dest), regs_.F(inst.src1), regs_.F(inst.src2)); break; case IROp::FDiv: - fpr.Map(inst); - FDIV(32, fpr.R(inst.dest), fpr.R(inst.src1), fpr.R(inst.src2)); + regs_.Map(inst); + FDIV(32, regs_.F(inst.dest), regs_.F(inst.src1), regs_.F(inst.src2)); break; case IROp::FSqrt: - fpr.Map(inst); - FSQRT(32, fpr.R(inst.dest), fpr.R(inst.src1)); + regs_.Map(inst); + FSQRT(32, regs_.F(inst.dest), regs_.F(inst.src1)); break; case IROp::FNeg: - fpr.Map(inst); - FNEG(32, fpr.R(inst.dest), fpr.R(inst.src1)); + regs_.Map(inst); + FNEG(32, regs_.F(inst.dest), regs_.F(inst.src1)); break; default: @@ -83,9 +83,9 @@ void RiscVJitBackend::CompIR_FCondAssign(IRInst inst) { bool maxCondition = inst.op == IROp::FMax; // FMin and FMax are used by VFPU and handle NAN/INF as just a larger exponent. - fpr.Map(inst); - FCLASS(32, SCRATCH1, fpr.R(inst.src1)); - FCLASS(32, SCRATCH2, fpr.R(inst.src2)); + regs_.Map(inst); + FCLASS(32, SCRATCH1, regs_.F(inst.src1)); + FCLASS(32, SCRATCH2, regs_.F(inst.src2)); // If either side is a NAN, it needs to participate in the comparison. OR(SCRATCH1, SCRATCH1, SCRATCH2); @@ -94,8 +94,8 @@ void RiscVJitBackend::CompIR_FCondAssign(IRInst inst) { FixupBranch useNormalCond = BEQ(SCRATCH1, R_ZERO); // Time to use bits... classify won't help because it ignores -NAN. - FMV(FMv::X, FMv::W, SCRATCH1, fpr.R(inst.src1)); - FMV(FMv::X, FMv::W, SCRATCH2, fpr.R(inst.src2)); + FMV(FMv::X, FMv::W, SCRATCH1, regs_.F(inst.src1)); + FMV(FMv::X, FMv::W, SCRATCH2, regs_.F(inst.src2)); // If both are negative, we flip the comparison (not two's compliment.) // We cheat and use RA... @@ -116,7 +116,7 @@ void RiscVJitBackend::CompIR_FCondAssign(IRInst inst) { MAX(SCRATCH1, SCRATCH1, SCRATCH2); SetJumpTarget(skipSwapCompare); } else { - RiscVReg isSrc1LowerReg = gpr.GetAndLockTempR(); + RiscVReg isSrc1LowerReg = regs_.GetAndLockTempR(); SLT(isSrc1LowerReg, SCRATCH1, SCRATCH2); // Flip the flag (to reverse the min/max) based on if both were negative. XOR(isSrc1LowerReg, isSrc1LowerReg, R_RA); @@ -129,14 +129,14 @@ void RiscVJitBackend::CompIR_FCondAssign(IRInst inst) { SetJumpTarget(useSrc1); } - FMV(FMv::W, FMv::X, fpr.R(inst.dest), SCRATCH1); + FMV(FMv::W, FMv::X, regs_.F(inst.dest), SCRATCH1); FixupBranch finish = J(); SetJumpTarget(useNormalCond); if (maxCondition) - FMAX(32, fpr.R(inst.dest), fpr.R(inst.src1), fpr.R(inst.src2)); + FMAX(32, regs_.F(inst.dest), regs_.F(inst.src1), regs_.F(inst.src2)); else - FMIN(32, fpr.R(inst.dest), fpr.R(inst.src1), fpr.R(inst.src2)); + FMIN(32, regs_.F(inst.dest), regs_.F(inst.src1), regs_.F(inst.src2)); SetJumpTarget(finish); } @@ -146,21 +146,21 @@ void RiscVJitBackend::CompIR_FAssign(IRInst inst) { switch (inst.op) { case IROp::FMov: if (inst.dest != inst.src1) { - fpr.Map(inst); - FMV(32, fpr.R(inst.dest), fpr.R(inst.src1)); + regs_.Map(inst); + FMV(32, regs_.F(inst.dest), regs_.F(inst.src1)); } break; case IROp::FAbs: - fpr.Map(inst); - FABS(32, fpr.R(inst.dest), fpr.R(inst.src1)); + regs_.Map(inst); + FABS(32, regs_.F(inst.dest), regs_.F(inst.src1)); break; case IROp::FSign: { - fpr.Map(inst); + regs_.Map(inst); // Check if it's negative zero, either 0x10/0x08 is zero. - FCLASS(32, SCRATCH1, fpr.R(inst.src1)); + FCLASS(32, SCRATCH1, regs_.F(inst.src1)); ANDI(SCRATCH1, SCRATCH1, 0x18); SEQZ(SCRATCH1, SCRATCH1); // Okay, it's zero if zero, 1 otherwise. Convert 1 to a constant 1.0. @@ -169,14 +169,14 @@ void RiscVJitBackend::CompIR_FAssign(IRInst inst) { LI(SCRATCH1, 1.0f); // Now we just need the sign from it. - FMV(FMv::X, FMv::W, SCRATCH2, fpr.R(inst.src1)); + FMV(FMv::X, FMv::W, SCRATCH2, regs_.F(inst.src1)); // Use a wall to isolate the sign, and combine. SRAIW(SCRATCH2, SCRATCH2, 31); SLLIW(SCRATCH2, SCRATCH2, 31); OR(SCRATCH1, SCRATCH1, SCRATCH2); SetJumpTarget(skipOne); - FMV(FMv::W, FMv::X, fpr.R(inst.dest), SCRATCH1); + FMV(FMv::W, FMv::X, regs_.F(inst.dest), SCRATCH1); break; } @@ -190,23 +190,23 @@ void RiscVJitBackend::CompIR_FRound(IRInst inst) { CONDITIONAL_DISABLE; // TODO: If this is followed by a GPR transfer, might want to combine. - fpr.Map(inst); + regs_.Map(inst); switch (inst.op) { case IROp::FRound: - FCVT(FConv::W, FConv::S, SCRATCH1, fpr.R(inst.src1), Round::NEAREST_EVEN); + FCVT(FConv::W, FConv::S, SCRATCH1, regs_.F(inst.src1), Round::NEAREST_EVEN); break; case IROp::FTrunc: - FCVT(FConv::W, FConv::S, SCRATCH1, fpr.R(inst.src1), Round::TOZERO); + FCVT(FConv::W, FConv::S, SCRATCH1, regs_.F(inst.src1), Round::TOZERO); break; case IROp::FCeil: - FCVT(FConv::W, FConv::S, SCRATCH1, fpr.R(inst.src1), Round::UP); + FCVT(FConv::W, FConv::S, SCRATCH1, regs_.F(inst.src1), Round::UP); break; case IROp::FFloor: - FCVT(FConv::W, FConv::S, SCRATCH1, fpr.R(inst.src1), Round::DOWN); + FCVT(FConv::W, FConv::S, SCRATCH1, regs_.F(inst.src1), Round::DOWN); break; default: @@ -214,7 +214,7 @@ void RiscVJitBackend::CompIR_FRound(IRInst inst) { break; } - FMV(FMv::W, FMv::X, fpr.R(inst.dest), SCRATCH1); + FMV(FMv::W, FMv::X, regs_.F(inst.dest), SCRATCH1); } void RiscVJitBackend::CompIR_FCvt(IRInst inst) { @@ -228,9 +228,9 @@ void RiscVJitBackend::CompIR_FCvt(IRInst inst) { case IROp::FCvtSW: // TODO: This is probably proceeded by a GPR transfer, might be ideal to combine. - fpr.Map(inst); - FMV(FMv::X, FMv::W, SCRATCH1, fpr.R(inst.src1)); - FCVT(FConv::S, FConv::W, fpr.R(inst.dest), SCRATCH1); + regs_.Map(inst); + FMV(FMv::X, FMv::W, SCRATCH1, regs_.F(inst.src1)); + FCVT(FConv::S, FConv::W, regs_.F(inst.dest), SCRATCH1); break; case IROp::FCvtScaledWS: @@ -243,17 +243,17 @@ void RiscVJitBackend::CompIR_FCvt(IRInst inst) { case 3: rm = Round::DOWN; break; } - tempReg = fpr.MapDirtyInTemp(inst.dest, inst.src1); + tempReg = regs_.MapFPRDirtyInTemp(inst.dest, inst.src1); // Prepare the double src1 and the multiplier. - FCVT(FConv::D, FConv::S, fpr.R(inst.dest), fpr.R(inst.src1)); + FCVT(FConv::D, FConv::S, regs_.F(inst.dest), regs_.F(inst.src1)); LI(SCRATCH1, 1UL << (inst.src2 & 0x1F)); FCVT(FConv::D, FConv::WU, tempReg, SCRATCH1, rm); - FMUL(64, fpr.R(inst.dest), fpr.R(inst.dest), tempReg, rm); + FMUL(64, regs_.F(inst.dest), regs_.F(inst.dest), tempReg, rm); // NAN and clamping should all be correct. - FCVT(FConv::W, FConv::D, SCRATCH1, fpr.R(inst.dest), rm); + FCVT(FConv::W, FConv::D, SCRATCH1, regs_.F(inst.dest), rm); // TODO: Could combine with a transfer, often is one... - FMV(FMv::W, FMv::X, fpr.R(inst.dest), SCRATCH1); + FMV(FMv::W, FMv::X, regs_.F(inst.dest), SCRATCH1); } else { CompIR_Generic(inst); } @@ -261,14 +261,14 @@ void RiscVJitBackend::CompIR_FCvt(IRInst inst) { case IROp::FCvtScaledSW: // TODO: This is probably proceeded by a GPR transfer, might be ideal to combine. - tempReg = fpr.MapDirtyInTemp(inst.dest, inst.src1); - FMV(FMv::X, FMv::W, SCRATCH1, fpr.R(inst.src1)); - FCVT(FConv::S, FConv::W, fpr.R(inst.dest), SCRATCH1); + tempReg = regs_.MapFPRDirtyInTemp(inst.dest, inst.src1); + FMV(FMv::X, FMv::W, SCRATCH1, regs_.F(inst.src1)); + FCVT(FConv::S, FConv::W, regs_.F(inst.dest), SCRATCH1); // Pre-divide so we can avoid any actual divide. LI(SCRATCH1, 1.0f / (1UL << (inst.src2 & 0x1F))); FMV(FMv::W, FMv::X, tempReg, SCRATCH1); - FMUL(32, fpr.R(inst.dest), fpr.R(inst.dest), tempReg); + FMUL(32, regs_.F(inst.dest), regs_.F(inst.dest), tempReg); break; default: @@ -286,48 +286,48 @@ void RiscVJitBackend::CompIR_FSat(IRInst inst) { FixupBranch skipHigher; switch (inst.op) { case IROp::FSat0_1: - tempReg = fpr.MapDirtyInTemp(inst.dest, inst.src1); + tempReg = regs_.MapFPRDirtyInTemp(inst.dest, inst.src1); if (inst.dest != inst.src1) - FMV(32, fpr.R(inst.dest), fpr.R(inst.src1)); + FMV(32, regs_.F(inst.dest), regs_.F(inst.src1)); // First, set SCRATCH1 = clamp to zero, SCRATCH2 = clamp to one. FCVT(FConv::S, FConv::W, tempReg, R_ZERO); // FLE here is intentional to convert -0.0 to +0.0. - FLE(32, SCRATCH1, fpr.R(inst.src1), tempReg); + FLE(32, SCRATCH1, regs_.F(inst.src1), tempReg); LI(SCRATCH2, 1.0f); FMV(FMv::W, FMv::X, tempReg, SCRATCH2); - FLT(32, SCRATCH2, tempReg, fpr.R(inst.src1)); + FLT(32, SCRATCH2, tempReg, regs_.F(inst.src1)); skipLower = BEQ(SCRATCH1, R_ZERO); - FCVT(FConv::S, FConv::W, fpr.R(inst.dest), R_ZERO); + FCVT(FConv::S, FConv::W, regs_.F(inst.dest), R_ZERO); finishLower = J(); SetJumpTarget(skipLower); skipHigher = BEQ(SCRATCH2, R_ZERO); // Still has 1.0 in it. - FMV(32, fpr.R(inst.dest), tempReg); + FMV(32, regs_.F(inst.dest), tempReg); SetJumpTarget(finishLower); SetJumpTarget(skipHigher); break; case IROp::FSatMinus1_1: - tempReg = fpr.MapDirtyInTemp(inst.dest, inst.src1); + tempReg = regs_.MapFPRDirtyInTemp(inst.dest, inst.src1); if (inst.dest != inst.src1) - FMV(32, fpr.R(inst.dest), fpr.R(inst.src1)); + FMV(32, regs_.F(inst.dest), regs_.F(inst.src1)); // First, set SCRATCH1 = clamp to negative, SCRATCH2 = clamp to positive. LI(SCRATCH2, -1.0f); FMV(FMv::W, FMv::X, tempReg, SCRATCH2); - FLT(32, SCRATCH1, fpr.R(inst.src1), tempReg); + FLT(32, SCRATCH1, regs_.F(inst.src1), tempReg); FNEG(32, tempReg, tempReg); - FLT(32, SCRATCH2, tempReg, fpr.R(inst.src1)); + FLT(32, SCRATCH2, tempReg, regs_.F(inst.src1)); // But we can actually do one branch, using sign-injection to keep the original sign. OR(SCRATCH1, SCRATCH1, SCRATCH2); skipLower = BEQ(SCRATCH1, R_ZERO); - FSGNJ(32, fpr.R(inst.dest), tempReg, fpr.R(inst.dest)); + FSGNJ(32, regs_.F(inst.dest), tempReg, regs_.F(inst.dest)); SetJumpTarget(skipLower); break; @@ -346,134 +346,134 @@ void RiscVJitBackend::CompIR_FCompare(IRInst inst) { case IROp::FCmp: switch (inst.dest) { case IRFpCompareMode::False: - gpr.SetGPRImm(IRREG_FPCOND, 0); + regs_.SetGPRImm(IRREG_FPCOND, 0); break; case IRFpCompareMode::EitherUnordered: - fpr.Map(inst); - gpr.MapGPR(IRREG_FPCOND, MIPSMap::NOINIT | MIPSMap::MARK_NORM32); - FCLASS(32, SCRATCH1, fpr.R(inst.src1)); - FCLASS(32, SCRATCH2, fpr.R(inst.src2)); + regs_.Map(inst); + regs_.MapGPR(IRREG_FPCOND, MIPSMap::NOINIT | MIPSMap::MARK_NORM32); + FCLASS(32, SCRATCH1, regs_.F(inst.src1)); + FCLASS(32, SCRATCH2, regs_.F(inst.src2)); OR(SCRATCH1, SCRATCH1, SCRATCH2); // NAN is 0x100 or 0x200. ANDI(SCRATCH1, SCRATCH1, 0x300); - SNEZ(gpr.R(IRREG_FPCOND), SCRATCH1); + SNEZ(regs_.R(IRREG_FPCOND), SCRATCH1); break; case IRFpCompareMode::EqualOrdered: - fpr.Map(inst); - gpr.MapGPR(IRREG_FPCOND, MIPSMap::NOINIT | MIPSMap::MARK_NORM32); - FEQ(32, gpr.R(IRREG_FPCOND), fpr.R(inst.src1), fpr.R(inst.src2)); + regs_.Map(inst); + regs_.MapGPR(IRREG_FPCOND, MIPSMap::NOINIT | MIPSMap::MARK_NORM32); + FEQ(32, regs_.R(IRREG_FPCOND), regs_.F(inst.src1), regs_.F(inst.src2)); break; case IRFpCompareMode::EqualUnordered: - fpr.Map(inst); - gpr.MapGPR(IRREG_FPCOND, MIPSMap::NOINIT | MIPSMap::MARK_NORM32); - FEQ(32, gpr.R(IRREG_FPCOND), fpr.R(inst.src1), fpr.R(inst.src2)); + regs_.Map(inst); + regs_.MapGPR(IRREG_FPCOND, MIPSMap::NOINIT | MIPSMap::MARK_NORM32); + FEQ(32, regs_.R(IRREG_FPCOND), regs_.F(inst.src1), regs_.F(inst.src2)); // Now let's just OR in the unordered check. - FCLASS(32, SCRATCH1, fpr.R(inst.src1)); - FCLASS(32, SCRATCH2, fpr.R(inst.src2)); + FCLASS(32, SCRATCH1, regs_.F(inst.src1)); + FCLASS(32, SCRATCH2, regs_.F(inst.src2)); OR(SCRATCH1, SCRATCH1, SCRATCH2); // NAN is 0x100 or 0x200. ANDI(SCRATCH1, SCRATCH1, 0x300); SNEZ(SCRATCH1, SCRATCH1); - OR(gpr.R(IRREG_FPCOND), gpr.R(IRREG_FPCOND), SCRATCH1); + OR(regs_.R(IRREG_FPCOND), regs_.R(IRREG_FPCOND), SCRATCH1); break; case IRFpCompareMode::LessEqualOrdered: - fpr.Map(inst); - gpr.MapGPR(IRREG_FPCOND, MIPSMap::NOINIT | MIPSMap::MARK_NORM32); - FLE(32, gpr.R(IRREG_FPCOND), fpr.R(inst.src1), fpr.R(inst.src2)); + regs_.Map(inst); + regs_.MapGPR(IRREG_FPCOND, MIPSMap::NOINIT | MIPSMap::MARK_NORM32); + FLE(32, regs_.R(IRREG_FPCOND), regs_.F(inst.src1), regs_.F(inst.src2)); break; case IRFpCompareMode::LessEqualUnordered: - fpr.Map(inst); - gpr.MapGPR(IRREG_FPCOND, MIPSMap::NOINIT | MIPSMap::MARK_NORM32); - FLT(32, gpr.R(IRREG_FPCOND), fpr.R(inst.src2), fpr.R(inst.src1)); - SEQZ(gpr.R(IRREG_FPCOND), gpr.R(IRREG_FPCOND)); + regs_.Map(inst); + regs_.MapGPR(IRREG_FPCOND, MIPSMap::NOINIT | MIPSMap::MARK_NORM32); + FLT(32, regs_.R(IRREG_FPCOND), regs_.F(inst.src2), regs_.F(inst.src1)); + SEQZ(regs_.R(IRREG_FPCOND), regs_.R(IRREG_FPCOND)); break; case IRFpCompareMode::LessOrdered: - fpr.Map(inst); - gpr.MapGPR(IRREG_FPCOND, MIPSMap::NOINIT | MIPSMap::MARK_NORM32); - FLT(32, gpr.R(IRREG_FPCOND), fpr.R(inst.src1), fpr.R(inst.src2)); + regs_.Map(inst); + regs_.MapGPR(IRREG_FPCOND, MIPSMap::NOINIT | MIPSMap::MARK_NORM32); + FLT(32, regs_.R(IRREG_FPCOND), regs_.F(inst.src1), regs_.F(inst.src2)); break; case IRFpCompareMode::LessUnordered: - fpr.Map(inst); - gpr.MapGPR(IRREG_FPCOND, MIPSMap::NOINIT | MIPSMap::MARK_NORM32); - FLE(32, gpr.R(IRREG_FPCOND), fpr.R(inst.src2), fpr.R(inst.src1)); - SEQZ(gpr.R(IRREG_FPCOND), gpr.R(IRREG_FPCOND)); + regs_.Map(inst); + regs_.MapGPR(IRREG_FPCOND, MIPSMap::NOINIT | MIPSMap::MARK_NORM32); + FLE(32, regs_.R(IRREG_FPCOND), regs_.F(inst.src2), regs_.F(inst.src1)); + SEQZ(regs_.R(IRREG_FPCOND), regs_.R(IRREG_FPCOND)); break; } break; case IROp::FCmovVfpuCC: - gpr.MapGPR(IRREG_VFPU_CC); - fpr.Map(inst); + regs_.MapGPR(IRREG_VFPU_CC); + regs_.Map(inst); if ((inst.src2 & 0xF) == 0) { - ANDI(SCRATCH1, gpr.R(IRREG_VFPU_CC), 1); + ANDI(SCRATCH1, regs_.R(IRREG_VFPU_CC), 1); } else if (cpu_info.RiscV_Zbs) { - BEXTI(SCRATCH1, gpr.R(IRREG_VFPU_CC), inst.src2 & 0xF); + BEXTI(SCRATCH1, regs_.R(IRREG_VFPU_CC), inst.src2 & 0xF); } else { - SRLI(SCRATCH1, gpr.R(IRREG_VFPU_CC), inst.src2 & 0xF); + SRLI(SCRATCH1, regs_.R(IRREG_VFPU_CC), inst.src2 & 0xF); ANDI(SCRATCH1, SCRATCH1, 1); } if ((inst.src2 >> 7) & 1) { FixupBranch skip = BEQ(SCRATCH1, R_ZERO); - FMV(32, fpr.R(inst.dest), fpr.R(inst.src1)); + FMV(32, regs_.F(inst.dest), regs_.F(inst.src1)); SetJumpTarget(skip); } else { FixupBranch skip = BNE(SCRATCH1, R_ZERO); - FMV(32, fpr.R(inst.dest), fpr.R(inst.src1)); + FMV(32, regs_.F(inst.dest), regs_.F(inst.src1)); SetJumpTarget(skip); } break; case IROp::FCmpVfpuBit: - gpr.MapGPR(IRREG_VFPU_CC, MIPSMap::DIRTY); + regs_.MapGPR(IRREG_VFPU_CC, MIPSMap::DIRTY); switch (VCondition(inst.dest & 0xF)) { case VC_EQ: - fpr.Map(inst); - FEQ(32, SCRATCH1, fpr.R(inst.src1), fpr.R(inst.src2)); + regs_.Map(inst); + FEQ(32, SCRATCH1, regs_.F(inst.src1), regs_.F(inst.src2)); break; case VC_NE: - fpr.Map(inst); + regs_.Map(inst); // We could almost negate FEQ, except NAN != NAN. // Anything != NAN is false and NAN != NAN is within that, so we only check one side. - FCLASS(32, SCRATCH2, fpr.R(inst.src2)); + FCLASS(32, SCRATCH2, regs_.F(inst.src2)); // NAN is 0x100 or 0x200. ANDI(SCRATCH2, SCRATCH2, 0x300); SNEZ(SCRATCH2, SCRATCH2); - FEQ(32, SCRATCH1, fpr.R(inst.src1), fpr.R(inst.src2)); + FEQ(32, SCRATCH1, regs_.F(inst.src1), regs_.F(inst.src2)); SEQZ(SCRATCH1, SCRATCH1); // Just OR in whether that side was a NAN so it's always not equal. OR(SCRATCH1, SCRATCH1, SCRATCH2); break; case VC_LT: - fpr.Map(inst); - FLT(32, SCRATCH1, fpr.R(inst.src1), fpr.R(inst.src2)); + regs_.Map(inst); + FLT(32, SCRATCH1, regs_.F(inst.src1), regs_.F(inst.src2)); break; case VC_LE: - fpr.Map(inst); - FLE(32, SCRATCH1, fpr.R(inst.src1), fpr.R(inst.src2)); + regs_.Map(inst); + FLE(32, SCRATCH1, regs_.F(inst.src1), regs_.F(inst.src2)); break; case VC_GT: - fpr.Map(inst); - FLT(32, SCRATCH1, fpr.R(inst.src2), fpr.R(inst.src1)); + regs_.Map(inst); + FLT(32, SCRATCH1, regs_.F(inst.src2), regs_.F(inst.src1)); break; case VC_GE: - fpr.Map(inst); - FLE(32, SCRATCH1, fpr.R(inst.src2), fpr.R(inst.src1)); + regs_.Map(inst); + FLE(32, SCRATCH1, regs_.F(inst.src2), regs_.F(inst.src1)); break; case VC_EZ: case VC_NZ: - fpr.MapFPR(inst.src1); + regs_.MapFPR(inst.src1); // Zero is either 0x10 or 0x08. - FCLASS(32, SCRATCH1, fpr.R(inst.src1)); + FCLASS(32, SCRATCH1, regs_.F(inst.src1)); ANDI(SCRATCH1, SCRATCH1, 0x18); if ((inst.dest & 4) == 0) SNEZ(SCRATCH1, SCRATCH1); @@ -482,9 +482,9 @@ void RiscVJitBackend::CompIR_FCompare(IRInst inst) { break; case VC_EN: case VC_NN: - fpr.MapFPR(inst.src1); + regs_.MapFPR(inst.src1); // NAN is either 0x100 or 0x200. - FCLASS(32, SCRATCH1, fpr.R(inst.src1)); + FCLASS(32, SCRATCH1, regs_.F(inst.src1)); ANDI(SCRATCH1, SCRATCH1, 0x300); if ((inst.dest & 4) == 0) SNEZ(SCRATCH1, SCRATCH1); @@ -493,9 +493,9 @@ void RiscVJitBackend::CompIR_FCompare(IRInst inst) { break; case VC_EI: case VC_NI: - fpr.MapFPR(inst.src1); + regs_.MapFPR(inst.src1); // Infinity is either 0x80 or 0x01. - FCLASS(32, SCRATCH1, fpr.R(inst.src1)); + FCLASS(32, SCRATCH1, regs_.F(inst.src1)); ANDI(SCRATCH1, SCRATCH1, 0x81); if ((inst.dest & 4) == 0) SNEZ(SCRATCH1, SCRATCH1); @@ -504,9 +504,9 @@ void RiscVJitBackend::CompIR_FCompare(IRInst inst) { break; case VC_ES: case VC_NS: - fpr.MapFPR(inst.src1); + regs_.MapFPR(inst.src1); // Infinity is either 0x80 or 0x01, NAN is either 0x100 or 0x200. - FCLASS(32, SCRATCH1, fpr.R(inst.src1)); + FCLASS(32, SCRATCH1, regs_.F(inst.src1)); ANDI(SCRATCH1, SCRATCH1, 0x381); if ((inst.dest & 4) == 0) SNEZ(SCRATCH1, SCRATCH1); @@ -521,15 +521,15 @@ void RiscVJitBackend::CompIR_FCompare(IRInst inst) { break; } - ANDI(gpr.R(IRREG_VFPU_CC), gpr.R(IRREG_VFPU_CC), ~(1 << (inst.dest >> 4))); + ANDI(regs_.R(IRREG_VFPU_CC), regs_.R(IRREG_VFPU_CC), ~(1 << (inst.dest >> 4))); if ((inst.dest >> 4) != 0) SLLI(SCRATCH1, SCRATCH1, inst.dest >> 4); - OR(gpr.R(IRREG_VFPU_CC), gpr.R(IRREG_VFPU_CC), SCRATCH1); + OR(regs_.R(IRREG_VFPU_CC), regs_.R(IRREG_VFPU_CC), SCRATCH1); break; case IROp::FCmpVfpuAggregate: - gpr.MapGPR(IRREG_VFPU_CC, MIPSMap::DIRTY); - ANDI(SCRATCH1, gpr.R(IRREG_VFPU_CC), inst.dest); + regs_.MapGPR(IRREG_VFPU_CC, MIPSMap::DIRTY); + ANDI(SCRATCH1, regs_.R(IRREG_VFPU_CC), inst.dest); // This is the "any bit", easy. SNEZ(SCRATCH2, SCRATCH1); // To compare to inst.dest for "all", let's simply subtract it and compare to zero. @@ -541,8 +541,8 @@ void RiscVJitBackend::CompIR_FCompare(IRInst inst) { OR(SCRATCH1, SCRATCH1, SCRATCH2); // Reject those any/all bits and replace them with our own. - ANDI(gpr.R(IRREG_VFPU_CC), gpr.R(IRREG_VFPU_CC), ~0x30); - OR(gpr.R(IRREG_VFPU_CC), gpr.R(IRREG_VFPU_CC), SCRATCH1); + ANDI(regs_.R(IRREG_VFPU_CC), regs_.R(IRREG_VFPU_CC), ~0x30); + OR(regs_.R(IRREG_VFPU_CC), regs_.R(IRREG_VFPU_CC), SCRATCH1); break; default: @@ -581,21 +581,20 @@ void RiscVJitBackend::CompIR_FSpecial(IRInst inst) { #endif auto callFuncF_F = [&](float (*func)(float)){ - gpr.FlushBeforeCall(); - fpr.FlushBeforeCall(); + regs_.FlushBeforeCall(); // It might be in a non-volatile register. - if (fpr.IsFPRMapped(inst.src1)) { - FMV(32, F10, fpr.R(inst.src1)); + if (regs_.IsFPRMapped(inst.src1)) { + FMV(32, F10, regs_.F(inst.src1)); } else { int offset = offsetof(MIPSState, f) + inst.src1 * 4; FL(32, F10, CTXREG, offset); } QuickCallFunction(func, SCRATCH1); - fpr.MapFPR(inst.dest, MIPSMap::NOINIT); + regs_.MapFPR(inst.dest, MIPSMap::NOINIT); // If it's already F10, we're done - MapReg doesn't actually overwrite the reg in that case. - if (fpr.R(inst.dest) != F10) { - FMV(32, fpr.R(inst.dest), F10); + if (regs_.F(inst.dest) != F10) { + FMV(32, regs_.F(inst.dest), F10); } }; @@ -610,27 +609,27 @@ void RiscVJitBackend::CompIR_FSpecial(IRInst inst) { break; case IROp::FRSqrt: - tempReg = fpr.MapDirtyInTemp(inst.dest, inst.src1); - FSQRT(32, fpr.R(inst.dest), fpr.R(inst.src1)); + tempReg = regs_.MapFPRDirtyInTemp(inst.dest, inst.src1); + FSQRT(32, regs_.F(inst.dest), regs_.F(inst.src1)); // Ugh, we can't really avoid a temp here. Probably not worth a permanent one. LI(SCRATCH1, 1.0f); FMV(FMv::W, FMv::X, tempReg, SCRATCH1); - FDIV(32, fpr.R(inst.dest), tempReg, fpr.R(inst.dest)); + FDIV(32, regs_.F(inst.dest), tempReg, regs_.F(inst.dest)); break; case IROp::FRecip: if (inst.dest != inst.src1) { // This is the easy case. - fpr.Map(inst); + regs_.Map(inst); LI(SCRATCH1, 1.0f); - FMV(FMv::W, FMv::X, fpr.R(inst.dest), SCRATCH1); - FDIV(32, fpr.R(inst.dest), fpr.R(inst.dest), fpr.R(inst.src1)); + FMV(FMv::W, FMv::X, regs_.F(inst.dest), SCRATCH1); + FDIV(32, regs_.F(inst.dest), regs_.F(inst.dest), regs_.F(inst.src1)); } else { - tempReg = fpr.MapDirtyInTemp(inst.dest, inst.src1); + tempReg = regs_.MapFPRDirtyInTemp(inst.dest, inst.src1); LI(SCRATCH1, 1.0f); FMV(FMv::W, FMv::X, tempReg, SCRATCH1); - FDIV(32, fpr.R(inst.dest), tempReg, fpr.R(inst.src1)); + FDIV(32, regs_.F(inst.dest), tempReg, regs_.F(inst.src1)); } break; diff --git a/Core/MIPS/RiscV/RiscVCompLoadStore.cpp b/Core/MIPS/RiscV/RiscVCompLoadStore.cpp index 223cb9abe1..e21c43ab9f 100644 --- a/Core/MIPS/RiscV/RiscVCompLoadStore.cpp +++ b/Core/MIPS/RiscV/RiscVCompLoadStore.cpp @@ -35,18 +35,18 @@ using namespace RiscVGen; using namespace RiscVJitConstants; void RiscVJitBackend::SetScratch1ToSrc1Address(IRReg src1) { - gpr.MapGPR(src1); + regs_.MapGPR(src1); #ifdef MASKED_PSP_MEMORY - SLLIW(SCRATCH1, gpr.R(src1), 2); + SLLIW(SCRATCH1, regs_.R(src1), 2); SRLIW(SCRATCH1, SCRATCH1, 2); ADD(SCRATCH1, SCRATCH1, MEMBASEREG); #else // Clear the top bits to be safe. if (cpu_info.RiscV_Zba) { - ADD_UW(SCRATCH1, gpr.R(src1), MEMBASEREG); + ADD_UW(SCRATCH1, regs_.R(src1), MEMBASEREG); } else { _assert_(XLEN == 64); - SLLI(SCRATCH1, gpr.R(src1), 32); + SLLI(SCRATCH1, regs_.R(src1), 32); SRLI(SCRATCH1, SCRATCH1, 32); ADD(SCRATCH1, SCRATCH1, MEMBASEREG); } @@ -66,7 +66,7 @@ int32_t RiscVJitBackend::AdjustForAddressOffset(RiscVGen::RiscVReg *reg, int32_t void RiscVJitBackend::CompIR_Load(IRInst inst) { CONDITIONAL_DISABLE; - gpr.SpillLockGPR(inst.dest, inst.src1); + regs_.SpillLockGPR(inst.dest, inst.src1); RiscVReg addrReg = INVALID_REG; if (inst.src1 == MIPS_REG_ZERO) { // This will get changed by AdjustForAddressOffset. @@ -74,14 +74,14 @@ void RiscVJitBackend::CompIR_Load(IRInst inst) { #ifdef MASKED_PSP_MEMORY inst.constant &= Memory::MEMVIEW32_MASK; #endif - } else if (jo.cachePointers || gpr.IsGPRMappedAsPointer(inst.src1)) { - addrReg = gpr.MapGPRAsPointer(inst.src1); + } else if (jo.cachePointers || regs_.IsGPRMappedAsPointer(inst.src1)) { + addrReg = regs_.MapGPRAsPointer(inst.src1); } else { SetScratch1ToSrc1Address(inst.src1); addrReg = SCRATCH1; } // With NOINIT, MapReg won't subtract MEMBASEREG even if dest == src1. - gpr.MapGPR(inst.dest, MIPSMap::NOINIT | MIPSMap::MARK_NORM32); + regs_.MapGPR(inst.dest, MIPSMap::NOINIT | MIPSMap::MARK_NORM32); s32 imm = AdjustForAddressOffset(&addrReg, inst.constant); @@ -89,29 +89,29 @@ void RiscVJitBackend::CompIR_Load(IRInst inst) { switch (inst.op) { case IROp::Load8: - LBU(gpr.R(inst.dest), addrReg, imm); + LBU(regs_.R(inst.dest), addrReg, imm); break; case IROp::Load8Ext: - LB(gpr.R(inst.dest), addrReg, imm); + LB(regs_.R(inst.dest), addrReg, imm); break; case IROp::Load16: - LHU(gpr.R(inst.dest), addrReg, imm); + LHU(regs_.R(inst.dest), addrReg, imm); break; case IROp::Load16Ext: - LH(gpr.R(inst.dest), addrReg, imm); + LH(regs_.R(inst.dest), addrReg, imm); break; case IROp::Load32: - LW(gpr.R(inst.dest), addrReg, imm); + LW(regs_.R(inst.dest), addrReg, imm); break; case IROp::Load32Linked: if (inst.dest != MIPS_REG_ZERO) - LW(gpr.R(inst.dest), addrReg, imm); - gpr.SetGPRImm(IRREG_LLBIT, 1); + LW(regs_.R(inst.dest), addrReg, imm); + regs_.SetGPRImm(IRREG_LLBIT, 1); break; default: @@ -146,8 +146,8 @@ void RiscVJitBackend::CompIR_FLoad(IRInst inst) { #ifdef MASKED_PSP_MEMORY inst.constant &= Memory::MEMVIEW32_MASK; #endif - } else if (jo.cachePointers || gpr.IsGPRMappedAsPointer(inst.src1)) { - addrReg = gpr.MapGPRAsPointer(inst.src1); + } else if (jo.cachePointers || regs_.IsGPRMappedAsPointer(inst.src1)) { + addrReg = regs_.MapGPRAsPointer(inst.src1); } else { SetScratch1ToSrc1Address(inst.src1); addrReg = SCRATCH1; @@ -159,8 +159,8 @@ void RiscVJitBackend::CompIR_FLoad(IRInst inst) { switch (inst.op) { case IROp::LoadFloat: - fpr.MapFPR(inst.dest, MIPSMap::NOINIT); - FL(32, fpr.R(inst.dest), addrReg, imm); + regs_.MapFPR(inst.dest, MIPSMap::NOINIT); + FL(32, regs_.F(inst.dest), addrReg, imm); break; default: @@ -179,8 +179,8 @@ void RiscVJitBackend::CompIR_VecLoad(IRInst inst) { #ifdef MASKED_PSP_MEMORY inst.constant &= Memory::MEMVIEW32_MASK; #endif - } else if (jo.cachePointers || gpr.IsGPRMappedAsPointer(inst.src1)) { - addrReg = gpr.MapGPRAsPointer(inst.src1); + } else if (jo.cachePointers || regs_.IsGPRMappedAsPointer(inst.src1)) { + addrReg = regs_.MapGPRAsPointer(inst.src1); } else { SetScratch1ToSrc1Address(inst.src1); addrReg = SCRATCH1; @@ -195,8 +195,8 @@ void RiscVJitBackend::CompIR_VecLoad(IRInst inst) { case IROp::LoadVec4: for (int i = 0; i < 4; ++i) { // Spilling is okay. - fpr.MapFPR(inst.dest + i, MIPSMap::NOINIT); - FL(32, fpr.R(inst.dest + i), addrReg, imm + 4 * i); + regs_.MapFPR(inst.dest + i, MIPSMap::NOINIT); + FL(32, regs_.F(inst.dest + i), addrReg, imm + 4 * i); } break; @@ -209,7 +209,7 @@ void RiscVJitBackend::CompIR_VecLoad(IRInst inst) { void RiscVJitBackend::CompIR_Store(IRInst inst) { CONDITIONAL_DISABLE; - gpr.SpillLockGPR(inst.src3, inst.src1); + regs_.SpillLockGPR(inst.src3, inst.src1); RiscVReg addrReg = INVALID_REG; if (inst.src1 == MIPS_REG_ZERO) { // This will get changed by AdjustForAddressOffset. @@ -217,15 +217,15 @@ void RiscVJitBackend::CompIR_Store(IRInst inst) { #ifdef MASKED_PSP_MEMORY inst.constant &= Memory::MEMVIEW32_MASK; #endif - } else if ((jo.cachePointers || gpr.IsGPRMappedAsPointer(inst.src1)) && inst.src3 != inst.src1) { - addrReg = gpr.MapGPRAsPointer(inst.src1); + } else if ((jo.cachePointers || regs_.IsGPRMappedAsPointer(inst.src1)) && inst.src3 != inst.src1) { + addrReg = regs_.MapGPRAsPointer(inst.src1); } else { SetScratch1ToSrc1Address(inst.src1); addrReg = SCRATCH1; } - RiscVReg valueReg = gpr.TryMapTempImm(inst.src3); + RiscVReg valueReg = regs_.TryMapTempImm(inst.src3); if (valueReg == INVALID_REG) - valueReg = gpr.MapGPR(inst.src3); + valueReg = regs_.MapGPR(inst.src3); s32 imm = AdjustForAddressOffset(&addrReg, inst.constant); @@ -255,7 +255,7 @@ void RiscVJitBackend::CompIR_CondStore(IRInst inst) { if (inst.op != IROp::Store32Conditional) INVALIDOP; - gpr.SpillLockGPR(IRREG_LLBIT, inst.src3, inst.src1); + regs_.SpillLockGPR(IRREG_LLBIT, inst.src3, inst.src1); RiscVReg addrReg = INVALID_REG; if (inst.src1 == MIPS_REG_ZERO) { // This will get changed by AdjustForAddressOffset. @@ -263,28 +263,28 @@ void RiscVJitBackend::CompIR_CondStore(IRInst inst) { #ifdef MASKED_PSP_MEMORY inst.constant &= Memory::MEMVIEW32_MASK; #endif - } else if ((jo.cachePointers || gpr.IsGPRMappedAsPointer(inst.src1)) && inst.src3 != inst.src1) { - addrReg = gpr.MapGPRAsPointer(inst.src1); + } else if ((jo.cachePointers || regs_.IsGPRMappedAsPointer(inst.src1)) && inst.src3 != inst.src1) { + addrReg = regs_.MapGPRAsPointer(inst.src1); } else { SetScratch1ToSrc1Address(inst.src1); addrReg = SCRATCH1; } - gpr.MapGPR(inst.src3, inst.dest == MIPS_REG_ZERO ? MIPSMap::INIT : MIPSMap::DIRTY); - gpr.MapGPR(IRREG_LLBIT); + regs_.MapGPR(inst.src3, inst.dest == MIPS_REG_ZERO ? MIPSMap::INIT : MIPSMap::DIRTY); + regs_.MapGPR(IRREG_LLBIT); s32 imm = AdjustForAddressOffset(&addrReg, inst.constant); // TODO: Safe memory? Or enough to have crash handler + validate? - FixupBranch condFailed = BEQ(gpr.R(IRREG_LLBIT), R_ZERO); - SW(gpr.R(inst.src3), addrReg, imm); + FixupBranch condFailed = BEQ(regs_.R(IRREG_LLBIT), R_ZERO); + SW(regs_.R(inst.src3), addrReg, imm); if (inst.dest != MIPS_REG_ZERO) { - LI(gpr.R(inst.dest), 1); + LI(regs_.R(inst.dest), 1); FixupBranch finish = J(); SetJumpTarget(condFailed); - LI(gpr.R(inst.dest), 0); + LI(regs_.R(inst.dest), 0); SetJumpTarget(finish); } else { SetJumpTarget(condFailed); @@ -317,8 +317,8 @@ void RiscVJitBackend::CompIR_FStore(IRInst inst) { #ifdef MASKED_PSP_MEMORY inst.constant &= Memory::MEMVIEW32_MASK; #endif - } else if (jo.cachePointers || gpr.IsGPRMappedAsPointer(inst.src1)) { - addrReg = gpr.MapGPRAsPointer(inst.src1); + } else if (jo.cachePointers || regs_.IsGPRMappedAsPointer(inst.src1)) { + addrReg = regs_.MapGPRAsPointer(inst.src1); } else { SetScratch1ToSrc1Address(inst.src1); addrReg = SCRATCH1; @@ -330,8 +330,8 @@ void RiscVJitBackend::CompIR_FStore(IRInst inst) { switch (inst.op) { case IROp::StoreFloat: - fpr.MapFPR(inst.src3); - FS(32, fpr.R(inst.src3), addrReg, imm); + regs_.MapFPR(inst.src3); + FS(32, regs_.F(inst.src3), addrReg, imm); break; default: @@ -350,8 +350,8 @@ void RiscVJitBackend::CompIR_VecStore(IRInst inst) { #ifdef MASKED_PSP_MEMORY inst.constant &= Memory::MEMVIEW32_MASK; #endif - } else if (jo.cachePointers || gpr.IsGPRMappedAsPointer(inst.src1)) { - addrReg = gpr.MapGPRAsPointer(inst.src1); + } else if (jo.cachePointers || regs_.IsGPRMappedAsPointer(inst.src1)) { + addrReg = regs_.MapGPRAsPointer(inst.src1); } else { SetScratch1ToSrc1Address(inst.src1); addrReg = SCRATCH1; @@ -366,8 +366,8 @@ void RiscVJitBackend::CompIR_VecStore(IRInst inst) { case IROp::StoreVec4: for (int i = 0; i < 4; ++i) { // Spilling is okay, though not ideal. - fpr.MapFPR(inst.src3 + i); - FS(32, fpr.R(inst.src3 + i), addrReg, imm + 4 * i); + regs_.MapFPR(inst.src3 + i); + FS(32, regs_.F(inst.src3 + i), addrReg, imm + 4 * i); } break; diff --git a/Core/MIPS/RiscV/RiscVCompSystem.cpp b/Core/MIPS/RiscV/RiscVCompSystem.cpp index b655bbda74..c7dbb531db 100644 --- a/Core/MIPS/RiscV/RiscVCompSystem.cpp +++ b/Core/MIPS/RiscV/RiscVCompSystem.cpp @@ -45,18 +45,18 @@ void RiscVJitBackend::CompIR_Basic(IRInst inst) { case IROp::SetConst: // Sign extend all constants. We get 0xFFFFFFFF sometimes, and it's more work to truncate. // The register only holds 32 bits in the end anyway. - gpr.SetGPRImm(inst.dest, (int32_t)inst.constant); + regs_.SetGPRImm(inst.dest, (int32_t)inst.constant); break; case IROp::SetConstF: - fpr.Map(inst); + regs_.Map(inst); if (inst.constant == 0) { - FCVT(FConv::S, FConv::W, fpr.R(inst.dest), R_ZERO); + FCVT(FConv::S, FConv::W, regs_.F(inst.dest), R_ZERO); } else { // TODO: In the future, could use FLI if it's approved. // Also, is FCVT faster? LI(SCRATCH1, (int32_t)inst.constant); - FMV(FMv::W, FMv::X, fpr.R(inst.dest), SCRATCH1); + FMV(FMv::W, FMv::X, regs_.F(inst.dest), SCRATCH1); } break; @@ -70,8 +70,8 @@ void RiscVJitBackend::CompIR_Basic(IRInst inst) { break; case IROp::SetPC: - gpr.Map(inst); - MovToPC(gpr.R(inst.src1)); + regs_.Map(inst); + MovToPC(regs_.R(inst.src1)); break; case IROp::SetPCConst: @@ -90,48 +90,48 @@ void RiscVJitBackend::CompIR_Transfer(IRInst inst) { switch (inst.op) { case IROp::SetCtrlVFPU: - gpr.SetGPRImm(IRREG_VFPU_CTRL_BASE + inst.dest, (int32_t)inst.constant); + regs_.SetGPRImm(IRREG_VFPU_CTRL_BASE + inst.dest, (int32_t)inst.constant); break; case IROp::SetCtrlVFPUReg: - gpr.MapDirtyIn(IRREG_VFPU_CTRL_BASE + inst.dest, inst.src1); - MV(gpr.R(IRREG_VFPU_CTRL_BASE + inst.dest), gpr.R(inst.src1)); - gpr.MarkGPRDirty(IRREG_VFPU_CTRL_BASE + inst.dest, gpr.IsNormalized32(inst.src1)); + regs_.MapGPRDirtyIn(IRREG_VFPU_CTRL_BASE + inst.dest, inst.src1); + MV(regs_.R(IRREG_VFPU_CTRL_BASE + inst.dest), regs_.R(inst.src1)); + regs_.MarkGPRDirty(IRREG_VFPU_CTRL_BASE + inst.dest, regs_.IsNormalized32(inst.src1)); break; case IROp::SetCtrlVFPUFReg: - gpr.MapGPR(IRREG_VFPU_CTRL_BASE + inst.dest, MIPSMap::NOINIT | MIPSMap::MARK_NORM32); - fpr.MapFPR(inst.src1); - FMV(FMv::X, FMv::W, gpr.R(IRREG_VFPU_CTRL_BASE + inst.dest), fpr.R(inst.src1)); + regs_.MapGPR(IRREG_VFPU_CTRL_BASE + inst.dest, MIPSMap::NOINIT | MIPSMap::MARK_NORM32); + regs_.MapFPR(inst.src1); + FMV(FMv::X, FMv::W, regs_.R(IRREG_VFPU_CTRL_BASE + inst.dest), regs_.F(inst.src1)); break; case IROp::FpCondFromReg: - gpr.MapDirtyIn(IRREG_FPCOND, inst.src1); - MV(gpr.R(IRREG_FPCOND), gpr.R(inst.src1)); + regs_.MapGPRDirtyIn(IRREG_FPCOND, inst.src1); + MV(regs_.R(IRREG_FPCOND), regs_.R(inst.src1)); break; case IROp::FpCondToReg: - gpr.MapDirtyIn(inst.dest, IRREG_FPCOND); - MV(gpr.R(inst.dest), gpr.R(IRREG_FPCOND)); - gpr.MarkGPRDirty(inst.dest, gpr.IsNormalized32(IRREG_FPCOND)); + regs_.MapGPRDirtyIn(inst.dest, IRREG_FPCOND); + MV(regs_.R(inst.dest), regs_.R(IRREG_FPCOND)); + regs_.MarkGPRDirty(inst.dest, regs_.IsNormalized32(IRREG_FPCOND)); break; case IROp::FpCtrlFromReg: - gpr.MapDirtyIn(IRREG_FPCOND, inst.src1, MapType::AVOID_LOAD_MARK_NORM32); + regs_.MapGPRDirtyIn(IRREG_FPCOND, inst.src1, MapType::AVOID_LOAD_MARK_NORM32); LI(SCRATCH1, 0x0181FFFF); - AND(SCRATCH1, gpr.R(inst.src1), SCRATCH1); + AND(SCRATCH1, regs_.R(inst.src1), SCRATCH1); // Extract the new fpcond value. if (cpu_info.RiscV_Zbs) { - BEXTI(gpr.R(IRREG_FPCOND), SCRATCH1, 23); + BEXTI(regs_.R(IRREG_FPCOND), SCRATCH1, 23); } else { - SRLI(gpr.R(IRREG_FPCOND), SCRATCH1, 23); - ANDI(gpr.R(IRREG_FPCOND), gpr.R(IRREG_FPCOND), 1); + SRLI(regs_.R(IRREG_FPCOND), SCRATCH1, 23); + ANDI(regs_.R(IRREG_FPCOND), regs_.R(IRREG_FPCOND), 1); } SW(SCRATCH1, CTXREG, IRREG_FCR31 * 4); break; case IROp::FpCtrlToReg: - gpr.MapDirtyIn(inst.dest, IRREG_FPCOND, MapType::AVOID_LOAD_MARK_NORM32); + regs_.MapGPRDirtyIn(inst.dest, IRREG_FPCOND, MapType::AVOID_LOAD_MARK_NORM32); // Load fcr31 and clear the fpcond bit. LW(SCRATCH1, CTXREG, IRREG_FCR31 * 4); if (cpu_info.RiscV_Zbs) { @@ -142,34 +142,34 @@ void RiscVJitBackend::CompIR_Transfer(IRInst inst) { } // Now get the correct fpcond bit. - ANDI(SCRATCH2, gpr.R(IRREG_FPCOND), 1); + ANDI(SCRATCH2, regs_.R(IRREG_FPCOND), 1); SLLI(SCRATCH2, SCRATCH2, 23); - OR(gpr.R(inst.dest), SCRATCH1, SCRATCH2); + OR(regs_.R(inst.dest), SCRATCH1, SCRATCH2); // Also update mips->fcr31 while we're here. - SW(gpr.R(inst.dest), CTXREG, IRREG_FCR31 * 4); + SW(regs_.R(inst.dest), CTXREG, IRREG_FCR31 * 4); break; case IROp::VfpuCtrlToReg: - gpr.MapDirtyIn(inst.dest, IRREG_VFPU_CTRL_BASE + inst.src1); - MV(gpr.R(inst.dest), gpr.R(IRREG_VFPU_CTRL_BASE + inst.src1)); - gpr.MarkGPRDirty(inst.dest, gpr.IsNormalized32(IRREG_VFPU_CTRL_BASE + inst.src1)); + regs_.MapGPRDirtyIn(inst.dest, IRREG_VFPU_CTRL_BASE + inst.src1); + MV(regs_.R(inst.dest), regs_.R(IRREG_VFPU_CTRL_BASE + inst.src1)); + regs_.MarkGPRDirty(inst.dest, regs_.IsNormalized32(IRREG_VFPU_CTRL_BASE + inst.src1)); break; case IROp::FMovFromGPR: - fpr.MapFPR(inst.dest, MIPSMap::NOINIT); - if (gpr.IsGPRImm(inst.src1) && gpr.GetGPRImm(inst.src1) == 0) { - FCVT(FConv::S, FConv::W, fpr.R(inst.dest), R_ZERO); + regs_.MapFPR(inst.dest, MIPSMap::NOINIT); + if (regs_.IsGPRImm(inst.src1) && regs_.GetGPRImm(inst.src1) == 0) { + FCVT(FConv::S, FConv::W, regs_.F(inst.dest), R_ZERO); } else { - gpr.MapGPR(inst.src1); - FMV(FMv::W, FMv::X, fpr.R(inst.dest), gpr.R(inst.src1)); + regs_.MapGPR(inst.src1); + FMV(FMv::W, FMv::X, regs_.F(inst.dest), regs_.R(inst.src1)); } break; case IROp::FMovToGPR: - gpr.MapGPR(inst.dest, MIPSMap::NOINIT | MIPSMap::MARK_NORM32); - fpr.MapFPR(inst.src1); - FMV(FMv::X, FMv::W, gpr.R(inst.dest), fpr.R(inst.src1)); + regs_.MapGPR(inst.dest, MIPSMap::NOINIT | MIPSMap::MARK_NORM32); + regs_.MapFPR(inst.src1); + FMV(FMv::X, FMv::W, regs_.R(inst.dest), regs_.F(inst.src1)); break; default: diff --git a/Core/MIPS/RiscV/RiscVCompVec.cpp b/Core/MIPS/RiscV/RiscVCompVec.cpp index c196c3f68b..7c85b26162 100644 --- a/Core/MIPS/RiscV/RiscVCompVec.cpp +++ b/Core/MIPS/RiscV/RiscVCompVec.cpp @@ -40,36 +40,36 @@ void RiscVJitBackend::CompIR_VecAssign(IRInst inst) { switch (inst.op) { case IROp::Vec4Init: - fpr.Map(inst); + regs_.Map(inst); // TODO: Check if FCVT/FMV/FL is better. switch ((Vec4Init)inst.src1) { case Vec4Init::AllZERO: for (int i = 0; i < 4; ++i) - FCVT(FConv::S, FConv::W, fpr.R(inst.dest + i), R_ZERO); + FCVT(FConv::S, FConv::W, regs_.F(inst.dest + i), R_ZERO); break; case Vec4Init::AllONE: LI(SCRATCH1, 1.0f); - FMV(FMv::W, FMv::X, fpr.R(inst.dest), SCRATCH1); + FMV(FMv::W, FMv::X, regs_.F(inst.dest), SCRATCH1); for (int i = 1; i < 4; ++i) - FMV(32, fpr.R(inst.dest + i), fpr.R(inst.dest)); + FMV(32, regs_.F(inst.dest + i), regs_.F(inst.dest)); break; case Vec4Init::AllMinusONE: LI(SCRATCH1, -1.0f); - FMV(FMv::W, FMv::X, fpr.R(inst.dest), SCRATCH1); + FMV(FMv::W, FMv::X, regs_.F(inst.dest), SCRATCH1); for (int i = 1; i < 4; ++i) - FMV(32, fpr.R(inst.dest + i), fpr.R(inst.dest)); + FMV(32, regs_.F(inst.dest + i), regs_.F(inst.dest)); break; case Vec4Init::Set_1000: LI(SCRATCH1, 1.0f); for (int i = 0; i < 4; ++i) { if (i == 0) - FMV(FMv::W, FMv::X, fpr.R(inst.dest + i), SCRATCH1); + FMV(FMv::W, FMv::X, regs_.F(inst.dest + i), SCRATCH1); else - FCVT(FConv::S, FConv::W, fpr.R(inst.dest + i), R_ZERO); + FCVT(FConv::S, FConv::W, regs_.F(inst.dest + i), R_ZERO); } break; @@ -77,9 +77,9 @@ void RiscVJitBackend::CompIR_VecAssign(IRInst inst) { LI(SCRATCH1, 1.0f); for (int i = 0; i < 4; ++i) { if (i == 1) - FMV(FMv::W, FMv::X, fpr.R(inst.dest + i), SCRATCH1); + FMV(FMv::W, FMv::X, regs_.F(inst.dest + i), SCRATCH1); else - FCVT(FConv::S, FConv::W, fpr.R(inst.dest + i), R_ZERO); + FCVT(FConv::S, FConv::W, regs_.F(inst.dest + i), R_ZERO); } break; @@ -87,9 +87,9 @@ void RiscVJitBackend::CompIR_VecAssign(IRInst inst) { LI(SCRATCH1, 1.0f); for (int i = 0; i < 4; ++i) { if (i == 2) - FMV(FMv::W, FMv::X, fpr.R(inst.dest + i), SCRATCH1); + FMV(FMv::W, FMv::X, regs_.F(inst.dest + i), SCRATCH1); else - FCVT(FConv::S, FConv::W, fpr.R(inst.dest + i), R_ZERO); + FCVT(FConv::S, FConv::W, regs_.F(inst.dest + i), R_ZERO); } break; @@ -97,9 +97,9 @@ void RiscVJitBackend::CompIR_VecAssign(IRInst inst) { LI(SCRATCH1, 1.0f); for (int i = 0; i < 4; ++i) { if (i == 3) - FMV(FMv::W, FMv::X, fpr.R(inst.dest + i), SCRATCH1); + FMV(FMv::W, FMv::X, regs_.F(inst.dest + i), SCRATCH1); else - FCVT(FConv::S, FConv::W, fpr.R(inst.dest + i), R_ZERO); + FCVT(FConv::S, FConv::W, regs_.F(inst.dest + i), R_ZERO); } break; } @@ -107,7 +107,7 @@ void RiscVJitBackend::CompIR_VecAssign(IRInst inst) { case IROp::Vec4Shuffle: if (inst.dest == inst.src1) { - RiscVReg tempReg = fpr.Map4DirtyInTemp(inst.dest, inst.src1); + RiscVReg tempReg = regs_.MapFPR4DirtyInTemp(inst.dest, inst.src1); // Try to find the least swaps needed to move in place, never worse than 6 FMVs. // Would be better with a vmerge and vector regs. @@ -121,13 +121,13 @@ void RiscVJitBackend::CompIR_VecAssign(IRInst inst) { auto moveChained = [&](const std::vector &lanes, bool rotate) { int firstState = state[lanes.front()]; if (rotate) - FMV(32, tempReg, fpr.R(inst.dest + lanes.front())); + FMV(32, tempReg, regs_.F(inst.dest + lanes.front())); for (size_t i = 1; i < lanes.size(); ++i) { - FMV(32, fpr.R(inst.dest + lanes[i - 1]), fpr.R(inst.dest + lanes[i])); + FMV(32, regs_.F(inst.dest + lanes[i - 1]), regs_.F(inst.dest + lanes[i])); state[lanes[i - 1]] = state[lanes[i]]; } if (rotate) { - FMV(32, fpr.R(inst.dest + lanes.back()), tempReg); + FMV(32, regs_.F(inst.dest + lanes.back()), tempReg); state[lanes.back()] = firstState; } }; @@ -158,26 +158,26 @@ void RiscVJitBackend::CompIR_VecAssign(IRInst inst) { moveChained({ neededByDepth2, neededBy, i, foundIn }, neededByDepth3 == foundIn); } } else { - fpr.Map(inst); + regs_.Map(inst); for (int i = 0; i < 4; ++i) { int lane = (inst.src2 >> (i * 2)) & 3; - FMV(32, fpr.R(inst.dest + i), fpr.R(inst.src1 + lane)); + FMV(32, regs_.F(inst.dest + i), regs_.F(inst.src1 + lane)); } } break; case IROp::Vec4Blend: - fpr.Map(inst); + regs_.Map(inst); for (int i = 0; i < 4; ++i) { int which = (inst.constant >> i) & 1; - FMV(32, fpr.R(inst.dest + i), fpr.R((which ? inst.src2 : inst.src1) + i)); + FMV(32, regs_.F(inst.dest + i), regs_.F((which ? inst.src2 : inst.src1) + i)); } break; case IROp::Vec4Mov: - fpr.Map(inst); + regs_.Map(inst); for (int i = 0; i < 4; ++i) - FMV(32, fpr.R(inst.dest + i), fpr.R(inst.src1 + i)); + FMV(32, regs_.F(inst.dest + i), regs_.F(inst.src1 + i)); break; default: @@ -191,47 +191,47 @@ void RiscVJitBackend::CompIR_VecArith(IRInst inst) { switch (inst.op) { case IROp::Vec4Add: - fpr.Map(inst); + regs_.Map(inst); for (int i = 0; i < 4; ++i) - FADD(32, fpr.R(inst.dest + i), fpr.R(inst.src1 + i), fpr.R(inst.src2 + i)); + FADD(32, regs_.F(inst.dest + i), regs_.F(inst.src1 + i), regs_.F(inst.src2 + i)); break; case IROp::Vec4Sub: - fpr.Map(inst); + regs_.Map(inst); for (int i = 0; i < 4; ++i) - FSUB(32, fpr.R(inst.dest + i), fpr.R(inst.src1 + i), fpr.R(inst.src2 + i)); + FSUB(32, regs_.F(inst.dest + i), regs_.F(inst.src1 + i), regs_.F(inst.src2 + i)); break; case IROp::Vec4Mul: - fpr.Map(inst); + regs_.Map(inst); for (int i = 0; i < 4; ++i) - FMUL(32, fpr.R(inst.dest + i), fpr.R(inst.src1 + i), fpr.R(inst.src2 + i)); + FMUL(32, regs_.F(inst.dest + i), regs_.F(inst.src1 + i), regs_.F(inst.src2 + i)); break; case IROp::Vec4Div: - fpr.Map(inst); + regs_.Map(inst); for (int i = 0; i < 4; ++i) - FDIV(32, fpr.R(inst.dest + i), fpr.R(inst.src1 + i), fpr.R(inst.src2 + i)); + FDIV(32, regs_.F(inst.dest + i), regs_.F(inst.src1 + i), regs_.F(inst.src2 + i)); break; case IROp::Vec4Scale: - fpr.SpillLockFPR(inst.src2); - fpr.MapFPR(inst.src2); - fpr.Map4DirtyIn(inst.dest, inst.src1); + regs_.SpillLockFPR(inst.src2); + regs_.MapFPR(inst.src2); + regs_.MapFPR4DirtyIn(inst.dest, inst.src1); for (int i = 0; i < 4; ++i) - FMUL(32, fpr.R(inst.dest + i), fpr.R(inst.src1 + i), fpr.R(inst.src2)); + FMUL(32, regs_.F(inst.dest + i), regs_.F(inst.src1 + i), regs_.F(inst.src2)); break; case IROp::Vec4Neg: - fpr.Map(inst); + regs_.Map(inst); for (int i = 0; i < 4; ++i) - FNEG(32, fpr.R(inst.dest + i), fpr.R(inst.src1 + i)); + FNEG(32, regs_.F(inst.dest + i), regs_.F(inst.src1 + i)); break; case IROp::Vec4Abs: - fpr.Map(inst); + regs_.Map(inst); for (int i = 0; i < 4; ++i) - FABS(32, fpr.R(inst.dest + i), fpr.R(inst.src1 + i)); + FABS(32, regs_.F(inst.dest + i), regs_.F(inst.src1 + i)); break; default: @@ -246,32 +246,32 @@ void RiscVJitBackend::CompIR_VecHoriz(IRInst inst) { switch (inst.op) { case IROp::Vec4Dot: // TODO: Maybe some option to call the slow accurate mode? - fpr.SpillLockFPR(inst.dest); + regs_.SpillLockFPR(inst.dest); for (int i = 0; i < 4; ++i) { - fpr.SpillLockFPR(inst.src1 + i); - fpr.SpillLockFPR(inst.src2 + i); + regs_.SpillLockFPR(inst.src1 + i); + regs_.SpillLockFPR(inst.src2 + i); } for (int i = 0; i < 4; ++i) { - fpr.MapFPR(inst.src1 + i); - fpr.MapFPR(inst.src2 + i); + regs_.MapFPR(inst.src1 + i); + regs_.MapFPR(inst.src2 + i); } - fpr.MapFPR(inst.dest, MIPSMap::NOINIT); + regs_.MapFPR(inst.dest, MIPSMap::NOINIT); if ((inst.dest < inst.src1 + 4 && inst.dest >= inst.src1) || (inst.dest < inst.src2 + 4 && inst.dest >= inst.src2)) { // This means inst.dest overlaps one of src1 or src2. We have to do that one first. // Technically this may impact -0.0 and such, but dots accurately need to be aligned anyway. for (int i = 0; i < 4; ++i) { if (inst.dest == inst.src1 + i || inst.dest == inst.src2 + i) - FMUL(32, fpr.R(inst.dest), fpr.R(inst.src1 + i), fpr.R(inst.src2 + i)); + FMUL(32, regs_.F(inst.dest), regs_.F(inst.src1 + i), regs_.F(inst.src2 + i)); } for (int i = 0; i < 4; ++i) { if (inst.dest != inst.src1 + i && inst.dest != inst.src2 + i) - FMADD(32, fpr.R(inst.dest), fpr.R(inst.src1 + i), fpr.R(inst.src2 + i), fpr.R(inst.dest)); + FMADD(32, regs_.F(inst.dest), regs_.F(inst.src1 + i), regs_.F(inst.src2 + i), regs_.F(inst.dest)); } } else { - FMUL(32, fpr.R(inst.dest), fpr.R(inst.src1), fpr.R(inst.src2)); + FMUL(32, regs_.F(inst.dest), regs_.F(inst.src1), regs_.F(inst.src2)); for (int i = 1; i < 4; ++i) - FMADD(32, fpr.R(inst.dest), fpr.R(inst.src1 + i), fpr.R(inst.src2 + i), fpr.R(inst.dest)); + FMADD(32, regs_.F(inst.dest), regs_.F(inst.src1 + i), regs_.F(inst.src2 + i), regs_.F(inst.dest)); } break; @@ -292,14 +292,14 @@ void RiscVJitBackend::CompIR_VecPack(IRInst inst) { break; case IROp::Vec4Unpack8To32: - fpr.SpillLockFPR(inst.src1); + regs_.SpillLockFPR(inst.src1); for (int i = 0; i < 4; ++i) - fpr.SpillLockFPR(inst.dest + i); - fpr.MapFPR(inst.src1); + regs_.SpillLockFPR(inst.dest + i); + regs_.MapFPR(inst.src1); for (int i = 0; i < 4; ++i) - fpr.MapFPR(inst.dest + i, MIPSMap::NOINIT); + regs_.MapFPR(inst.dest + i, MIPSMap::NOINIT); - FMV(FMv::X, FMv::W, SCRATCH2, fpr.R(inst.src1)); + FMV(FMv::X, FMv::W, SCRATCH2, regs_.F(inst.src1)); for (int i = 0; i < 4; ++i) { // Mask using walls. if (i != 0) { @@ -308,49 +308,49 @@ void RiscVJitBackend::CompIR_VecPack(IRInst inst) { } else { SLLI(SCRATCH1, SCRATCH2, 24); } - FMV(FMv::W, FMv::X, fpr.R(inst.dest + i), SCRATCH1); + FMV(FMv::W, FMv::X, regs_.F(inst.dest + i), SCRATCH1); } break; case IROp::Vec2Unpack16To32: - fpr.SpillLockFPR(inst.src1); + regs_.SpillLockFPR(inst.src1); for (int i = 0; i < 2; ++i) - fpr.SpillLockFPR(inst.dest + i); - fpr.MapFPR(inst.src1); + regs_.SpillLockFPR(inst.dest + i); + regs_.MapFPR(inst.src1); for (int i = 0; i < 2; ++i) - fpr.MapFPR(inst.dest + i, MIPSMap::NOINIT); + regs_.MapFPR(inst.dest + i, MIPSMap::NOINIT); - FMV(FMv::X, FMv::W, SCRATCH2, fpr.R(inst.src1)); + FMV(FMv::X, FMv::W, SCRATCH2, regs_.F(inst.src1)); SLLI(SCRATCH1, SCRATCH2, 16); - FMV(FMv::W, FMv::X, fpr.R(inst.dest), SCRATCH1); + FMV(FMv::W, FMv::X, regs_.F(inst.dest), SCRATCH1); SRLI(SCRATCH1, SCRATCH2, 16); SLLI(SCRATCH1, SCRATCH1, 16); - FMV(FMv::W, FMv::X, fpr.R(inst.dest + 1), SCRATCH1); + FMV(FMv::W, FMv::X, regs_.F(inst.dest + 1), SCRATCH1); break; case IROp::Vec4DuplicateUpperBitsAndShift1: - fpr.Map(inst); + regs_.Map(inst); for (int i = 0; i < 4; i++) { - FMV(FMv::X, FMv::W, SCRATCH1, fpr.R(inst.src1 + i)); + FMV(FMv::X, FMv::W, SCRATCH1, regs_.F(inst.src1 + i)); SRLIW(SCRATCH2, SCRATCH1, 8); OR(SCRATCH1, SCRATCH1, SCRATCH2); SRLIW(SCRATCH2, SCRATCH1, 16); OR(SCRATCH1, SCRATCH1, SCRATCH2); SRLIW(SCRATCH1, SCRATCH1, 1); - FMV(FMv::W, FMv::X, fpr.R(inst.dest + i), SCRATCH1); + FMV(FMv::W, FMv::X, regs_.F(inst.dest + i), SCRATCH1); } break; case IROp::Vec4Pack31To8: - fpr.SpillLockFPR(inst.dest); + regs_.SpillLockFPR(inst.dest); for (int i = 0; i < 4; ++i) { - fpr.SpillLockFPR(inst.src1 + i); - fpr.MapFPR(inst.src1 + i); + regs_.SpillLockFPR(inst.src1 + i); + regs_.MapFPR(inst.src1 + i); } - fpr.MapFPR(inst.dest, MIPSMap::NOINIT); + regs_.MapFPR(inst.dest, MIPSMap::NOINIT); for (int i = 0; i < 4; ++i) { - FMV(FMv::X, FMv::W, SCRATCH1, fpr.R(inst.src1 + i)); + FMV(FMv::X, FMv::W, SCRATCH1, regs_.F(inst.src1 + i)); SRLI(SCRATCH1, SCRATCH1, 23); if (i == 0) { ANDI(SCRATCH2, SCRATCH1, 0xFF); @@ -361,13 +361,13 @@ void RiscVJitBackend::CompIR_VecPack(IRInst inst) { } } - FMV(FMv::W, FMv::X, fpr.R(inst.dest), SCRATCH2); + FMV(FMv::W, FMv::X, regs_.F(inst.dest), SCRATCH2); break; case IROp::Vec2Pack32To16: - fpr.MapDirtyInIn(inst.dest, inst.src1, inst.src1 + 1); - FMV(FMv::X, FMv::W, SCRATCH1, fpr.R(inst.src1)); - FMV(FMv::X, FMv::W, SCRATCH2, fpr.R(inst.src1 + 1)); + regs_.MapFPRDirtyInIn(inst.dest, inst.src1, inst.src1 + 1); + FMV(FMv::X, FMv::W, SCRATCH1, regs_.F(inst.src1)); + FMV(FMv::X, FMv::W, SCRATCH2, regs_.F(inst.src1 + 1)); // Keep in mind, this was sign-extended, so we have to zero the upper. SLLI(SCRATCH1, SCRATCH1, XLEN - 32); // Now we just set (SCRATCH2 & 0xFFFF0000) | SCRATCH1. @@ -377,7 +377,7 @@ void RiscVJitBackend::CompIR_VecPack(IRInst inst) { SLLI(SCRATCH2, SCRATCH2, 16); OR(SCRATCH1, SCRATCH1, SCRATCH2); // Okay, to the floating point register. - FMV(FMv::W, FMv::X, fpr.R(inst.dest), SCRATCH1); + FMV(FMv::W, FMv::X, regs_.F(inst.dest), SCRATCH1); break; default: @@ -391,9 +391,9 @@ void RiscVJitBackend::CompIR_VecClamp(IRInst inst) { switch (inst.op) { case IROp::Vec4ClampToZero: - fpr.Map(inst); + regs_.Map(inst); for (int i = 0; i < 4; i++) { - FMV(FMv::X, FMv::W, SCRATCH1, fpr.R(inst.src1 + i)); + FMV(FMv::X, FMv::W, SCRATCH1, regs_.F(inst.src1 + i)); SRAIW(SCRATCH2, SCRATCH1, 31); if (cpu_info.RiscV_Zbb) { ANDN(SCRATCH1, SCRATCH1, SCRATCH2); @@ -401,7 +401,7 @@ void RiscVJitBackend::CompIR_VecClamp(IRInst inst) { NOT(SCRATCH2, SCRATCH2); AND(SCRATCH1, SCRATCH1, SCRATCH2); } - FMV(FMv::W, FMv::X, fpr.R(inst.dest + i), SCRATCH1); + FMV(FMv::W, FMv::X, regs_.F(inst.dest + i), SCRATCH1); } break; diff --git a/Core/MIPS/RiscV/RiscVJit.cpp b/Core/MIPS/RiscV/RiscVJit.cpp index b31e762d39..1e9e4ef04c 100644 --- a/Core/MIPS/RiscV/RiscVJit.cpp +++ b/Core/MIPS/RiscV/RiscVJit.cpp @@ -32,7 +32,7 @@ static constexpr int MIN_BLOCK_NORMAL_LEN = 16; static constexpr int MIN_BLOCK_EXIT_LEN = 8; RiscVJitBackend::RiscVJitBackend(JitOptions &jitopt, IRBlockCache &blocks) - : IRNativeBackend(blocks), jo(jitopt), gpr(&jo), fpr(&jo) { + : IRNativeBackend(blocks), jo(jitopt), regs_(&jo) { // Automatically disable incompatible options. if (((intptr_t)Memory::base & 0x00000000FFFFFFFFUL) != 0) { jo.enablePointerify = false; @@ -43,8 +43,7 @@ RiscVJitBackend::RiscVJitBackend(JitOptions &jitopt, IRBlockCache &blocks) AllocCodeSpace(1024 * 1024 * 16); SetAutoCompress(true); - gpr.Init(this); - fpr.Init(this); + regs_.Init(this); } RiscVJitBackend::~RiscVJitBackend() { @@ -76,23 +75,19 @@ bool RiscVJitBackend::CompileBlock(IRBlock *block, int block_num, bool preload) block->SetTargetOffset((int)GetOffset(blockStart)); compilingBlockNum_ = block_num; - gpr.Start(block); - fpr.Start(block); + regs_.Start(block); std::map addresses; for (int i = 0; i < block->GetNumInstructions(); ++i) { const IRInst &inst = block->GetInstructions()[i]; - gpr.SetIRIndex(i); - fpr.SetIRIndex(i); + regs_.SetIRIndex(i); // TODO: This might be a little wasteful when compiling if we're not debugging jit... addresses[GetCodePtr()] = inst; CompileIRInst(inst); - if (jo.Disabled(JitDisable::REGALLOC_GPR)) - gpr.FlushAll(); - if (jo.Disabled(JitDisable::REGALLOC_FPR)) - fpr.FlushAll(); + if (jo.Disabled(JitDisable::REGALLOC_GPR) || jo.Disabled(JitDisable::REGALLOC_FPR)) + regs_.FlushAll(jo.Disabled(JitDisable::REGALLOC_GPR), jo.Disabled(JitDisable::REGALLOC_FPR)); // Safety check, in case we get a bunch of really large jit ops without a lot of branching. if (GetSpaceLeft() < 0x800) { @@ -252,8 +247,7 @@ void RiscVJitBackend::CompIR_Interpret(IRInst inst) { } void RiscVJitBackend::FlushAll() { - gpr.FlushAll(); - fpr.FlushAll(); + regs_.FlushAll(); } bool RiscVJitBackend::DescribeCodePtr(const u8 *ptr, std::string &name) const { @@ -355,12 +349,12 @@ void RiscVJitBackend::NormalizeSrc12(IRInst inst, RiscVReg *lhs, RiscVReg *rhs, RiscVReg RiscVJitBackend::NormalizeR(IRReg rs, IRReg rd, RiscVReg tempReg) { // For proper compare, we must sign extend so they both match or don't match. // But don't change pointers, in case one is SP (happens in LittleBigPlanet.) - if (gpr.IsGPRImm(rs) && gpr.GetGPRImm(rs) == 0) { + if (regs_.IsGPRImm(rs) && regs_.GetGPRImm(rs) == 0) { return R_ZERO; - } else if (gpr.IsGPRMappedAsPointer(rs) || rs == rd) { - return gpr.Normalize32(rs, tempReg); + } else if (regs_.IsGPRMappedAsPointer(rs) || rs == rd) { + return regs_.Normalize32(rs, tempReg); } else { - return gpr.Normalize32(rs); + return regs_.Normalize32(rs); } } diff --git a/Core/MIPS/RiscV/RiscVJit.h b/Core/MIPS/RiscV/RiscVJit.h index 228fce48ab..46448c4c71 100644 --- a/Core/MIPS/RiscV/RiscVJit.h +++ b/Core/MIPS/RiscV/RiscVJit.h @@ -25,7 +25,6 @@ #include "Core/MIPS/JitCommon/JitState.h" #include "Core/MIPS/JitCommon/JitCommon.h" #include "Core/MIPS/RiscV/RiscVRegCache.h" -#include "Core/MIPS/RiscV/RiscVRegCacheFPU.h" namespace MIPSComp { @@ -112,8 +111,7 @@ private: RiscVGen::RiscVReg NormalizeR(IRReg rs, IRReg rd, RiscVGen::RiscVReg tempReg); JitOptions &jo; - RiscVRegCache gpr; - RiscVRegCacheFPU fpr; + RiscVRegCache regs_; const u8 *outerLoop_ = nullptr; const u8 *outerLoopPCInSCRATCH1_ = nullptr; diff --git a/Core/MIPS/RiscV/RiscVRegCache.cpp b/Core/MIPS/RiscV/RiscVRegCache.cpp index e0351b0b4a..f172b6ef67 100644 --- a/Core/MIPS/RiscV/RiscVRegCache.cpp +++ b/Core/MIPS/RiscV/RiscVRegCache.cpp @@ -31,8 +31,10 @@ using namespace RiscVJitConstants; RiscVRegCache::RiscVRegCache(MIPSComp::JitOptions *jo) : IRNativeRegCacheBase(jo) { - // TODO: Move to using for FPRs and VPRs too? - config_.totalNativeRegs = NUM_RVREG; + // TODO: Update these when using RISC-V V. + config_.totalNativeRegs = NUM_RVGPR + NUM_RVFPR; + config_.mapUseVRegs = false; + config_.mapSIMD = false; } void RiscVRegCache::Init(RiscVEmitter *emitter) { @@ -54,23 +56,40 @@ void RiscVRegCache::SetupInitialRegs() { } const int *RiscVRegCache::GetAllocationOrder(MIPSLoc type, int &count, int &base) const { - _assert_(type == MIPSLoc::REG); - // X8 and X9 are the most ideal for static alloc because they can be used with compression. - // Otherwise we stick to saved regs - might not be necessary. - static const int allocationOrder[] = { - X8, X9, X12, X13, X14, X15, X5, X6, X7, X16, X17, X18, X19, X20, X21, X22, X23, X28, X29, X30, X31, - }; - static const int allocationOrderStaticAlloc[] = { - X12, X13, X14, X15, X5, X6, X7, X16, X17, X21, X22, X23, X28, X29, X30, X31, - }; - base = X0; - if (jo_->useStaticAlloc) { - count = ARRAY_SIZE(allocationOrderStaticAlloc); - return allocationOrderStaticAlloc; - } else { + + if (type == MIPSLoc::REG) { + // X8 and X9 are the most ideal for static alloc because they can be used with compression. + // Otherwise we stick to saved regs - might not be necessary. + static const int allocationOrder[] = { + X8, X9, X12, X13, X14, X15, X5, X6, X7, X16, X17, X18, X19, X20, X21, X22, X23, X28, X29, X30, X31, + }; + static const int allocationOrderStaticAlloc[] = { + X12, X13, X14, X15, X5, X6, X7, X16, X17, X21, X22, X23, X28, X29, X30, X31, + }; + + if (jo_->useStaticAlloc) { + count = ARRAY_SIZE(allocationOrderStaticAlloc); + return allocationOrderStaticAlloc; + } else { + count = ARRAY_SIZE(allocationOrder); + return allocationOrder; + } + } else if (type == MIPSLoc::FREG) { + // F8 through F15 are used for compression, so they are great. + // TODO: Maybe we could remove some saved regs since we rarely need that many? Or maybe worth it? + static const int allocationOrder[] = { + F8, F9, F10, F11, F12, F13, F14, F15, + F0, F1, F2, F3, F4, F5, F6, F7, + F16, F17, F18, F19, F20, F21, F22, F23, F24, F25, F26, F27, F28, F29, F30, F31, + }; + count = ARRAY_SIZE(allocationOrder); return allocationOrder; + } else { + _assert_msg_(false, "Allocation order not yet implemented"); + count = 0; + return nullptr; } } @@ -116,14 +135,18 @@ void RiscVRegCache::EmitSaveStaticRegisters() { void RiscVRegCache::FlushBeforeCall() { // These registers are not preserved by function calls. + // They match between X0 and F0, conveniently. for (int i = 5; i <= 7; ++i) { - FlushNativeReg(i); + FlushNativeReg(X0 + i); + FlushNativeReg(F0 + i); } for (int i = 10; i <= 17; ++i) { - FlushNativeReg(i); + FlushNativeReg(X0 + i); + FlushNativeReg(F0 + i); } for (int i = 28; i <= 31; ++i) { - FlushNativeReg(i); + FlushNativeReg(X0 + i); + FlushNativeReg(F0 + i); } } @@ -232,7 +255,7 @@ RiscVReg RiscVRegCache::MapGPRAsPointer(IRReg reg) { return (RiscVReg)MapNativeRegAsPointer(reg); } -void RiscVRegCache::MapDirtyIn(IRReg rd, IRReg rs, MapType type) { +void RiscVRegCache::MapGPRDirtyIn(IRReg rd, IRReg rs, MapType type) { SpillLockGPR(rd, rs); bool load = type == MapType::ALWAYS_LOAD || rd == rs; MIPSMap norm32 = type == MapType::AVOID_LOAD_MARK_NORM32 ? MIPSMap::MARK_NORM32 : MIPSMap::INIT; @@ -241,7 +264,7 @@ void RiscVRegCache::MapDirtyIn(IRReg rd, IRReg rs, MapType type) { ReleaseSpillLockGPR(rd, rs); } -void RiscVRegCache::MapDirtyDirtyInIn(IRReg rd1, IRReg rd2, IRReg rs, IRReg rt, MapType type) { +void RiscVRegCache::MapGPRDirtyDirtyInIn(IRReg rd1, IRReg rd2, IRReg rs, IRReg rt, MapType type) { SpillLockGPR(rd1, rd2, rs, rt); bool load1 = type == MapType::ALWAYS_LOAD || (rd1 == rs || rd1 == rt); bool load2 = type == MapType::ALWAYS_LOAD || (rd2 == rs || rd2 == rt); @@ -253,6 +276,61 @@ void RiscVRegCache::MapDirtyDirtyInIn(IRReg rd1, IRReg rd2, IRReg rs, IRReg rt, ReleaseSpillLockGPR(rd1, rd2, rs, rt); } +RiscVReg RiscVRegCache::MapFPR(IRReg mipsReg, MIPSMap mapFlags) { + _dbg_assert_(IsValidFPR(mipsReg)); + _dbg_assert_(mr[mipsReg + 32].loc == MIPSLoc::MEM || mr[mipsReg + 32].loc == MIPSLoc::FREG); + + IRNativeReg nreg = MapNativeReg(MIPSLoc::FREG, mipsReg + 32, 1, mapFlags); + if (nreg != -1) + return (RiscVReg)nreg; + return INVALID_REG; +} + +void RiscVRegCache::MapFPRDirtyInIn(IRReg rd, IRReg rs, IRReg rt, bool avoidLoad) { + SpillLockFPR(rd, rs, rt); + bool load = !avoidLoad || (rd == rs || rd == rt); + MapFPR(rd, load ? MIPSMap::DIRTY : MIPSMap::NOINIT); + MapFPR(rt); + MapFPR(rs); + ReleaseSpillLockFPR(rd, rs, rt); +} + +RiscVReg RiscVRegCache::MapFPRDirtyInTemp(IRReg rd, IRReg rs, bool avoidLoad) { + SpillLockFPR(rd, rs); + bool load = !avoidLoad || rd == rs; + MapFPR(rd, load ? MIPSMap::DIRTY : MIPSMap::NOINIT); + MapFPR(rs); + RiscVReg temp = (RiscVReg)AllocateReg(MIPSLoc::FREG); + ReleaseSpillLockFPR(rd, rs); + return temp; +} + +void RiscVRegCache::MapFPR4DirtyIn(IRReg rdbase, IRReg rsbase, bool avoidLoad) { + for (int i = 0; i < 4; ++i) + SpillLockFPR(rdbase + i, rsbase + i); + bool load = !avoidLoad || (rdbase < rsbase + 4 && rdbase + 4 > rsbase); + for (int i = 0; i < 4; ++i) + MapFPR(rdbase + i, load ? MIPSMap::DIRTY : MIPSMap::NOINIT); + for (int i = 0; i < 4; ++i) + MapFPR(rsbase + i); + for (int i = 0; i < 4; ++i) + ReleaseSpillLockFPR(rdbase + i, rsbase + i); +} + +RiscVReg RiscVRegCache::MapFPR4DirtyInTemp(IRReg rdbase, IRReg rsbase, bool avoidLoad) { + for (int i = 0; i < 4; ++i) + SpillLockFPR(rdbase + i, rsbase + i); + bool load = !avoidLoad || (rdbase < rsbase + 4 && rdbase + 4 > rsbase); + for (int i = 0; i < 4; ++i) + MapFPR(rdbase + i, load ? MIPSMap::DIRTY : MIPSMap::NOINIT); + for (int i = 0; i < 4; ++i) + MapFPR(rsbase + i); + RiscVReg temp = (RiscVReg)AllocateReg(MIPSLoc::FREG); + for (int i = 0; i < 4; ++i) + ReleaseSpillLockFPR(rdbase + i, rsbase + i); + return temp; +} + void RiscVRegCache::AdjustNativeRegAsPtr(IRNativeReg nreg, bool state) { RiscVReg r = (RiscVReg)(X0 + nreg); _assert_(r >= X0 && r <= X31); @@ -286,32 +364,54 @@ void RiscVRegCache::AdjustNativeRegAsPtr(IRNativeReg nreg, bool state) { void RiscVRegCache::LoadNativeReg(IRNativeReg nreg, IRReg first, int lanes) { RiscVReg r = (RiscVReg)(X0 + nreg); - _dbg_assert_(r > X0 && r <= X31); + _dbg_assert_(r > X0); _dbg_assert_(first != MIPS_REG_ZERO); - // Multilane not yet supported. - _assert_(lanes == 1 || (lanes == 2 && first == IRREG_LO)); - if (lanes == 1) - emit_->LW(r, CTXREG, GetMipsRegOffset(first)); - else if (lanes == 2) - emit_->LD(r, CTXREG, GetMipsRegOffset(first)); - else - _assert_(false); - nr[nreg].normalized32 = true; + if (r <= X31) { + // Multilane not yet supported. + _assert_(lanes == 1 || (lanes == 2 && first == IRREG_LO)); + if (lanes == 1) + emit_->LW(r, CTXREG, GetMipsRegOffset(first)); + else if (lanes == 2) + emit_->LD(r, CTXREG, GetMipsRegOffset(first)); + else + _assert_(false); + nr[nreg].normalized32 = true; + } else { + _dbg_assert_(r >= F0 && r <= F31); + // Multilane not yet supported. + _assert_(lanes == 1); + if (mr[first].loc == MIPSLoc::FREG) { + emit_->FL(32, r, CTXREG, GetMipsRegOffset(first)); + } else { + _assert_msg_(mr[first].loc == MIPSLoc::FREG, "Cannot store this type: %d", (int)mr[first].loc); + } + } } void RiscVRegCache::StoreNativeReg(IRNativeReg nreg, IRReg first, int lanes) { RiscVReg r = (RiscVReg)(X0 + nreg); - _dbg_assert_(r > X0 && r <= X31); + _dbg_assert_(r > X0); _dbg_assert_(first != MIPS_REG_ZERO); - // Multilane not yet supported. - _assert_(lanes == 1 || (lanes == 2 && first == IRREG_LO)); - _assert_(mr[first].loc == MIPSLoc::REG || mr[first].loc == MIPSLoc::REG_IMM); - if (lanes == 1) - emit_->SW(r, CTXREG, GetMipsRegOffset(first)); - else if (lanes == 2) - emit_->SD(r, CTXREG, GetMipsRegOffset(first)); - else - _assert_(false); + if (r <= X31) { + // Multilane not yet supported. + _assert_(lanes == 1 || (lanes == 2 && first == IRREG_LO)); + _assert_(mr[first].loc == MIPSLoc::REG || mr[first].loc == MIPSLoc::REG_IMM); + if (lanes == 1) + emit_->SW(r, CTXREG, GetMipsRegOffset(first)); + else if (lanes == 2) + emit_->SD(r, CTXREG, GetMipsRegOffset(first)); + else + _assert_(false); + } else { + _dbg_assert_(r >= F0 && r <= F31); + // Multilane not yet supported. + _assert_(lanes == 1); + if (mr[first].loc == MIPSLoc::FREG) { + emit_->FS(32, r, CTXREG, GetMipsRegOffset(first)); + } else { + _assert_msg_(mr[first].loc == MIPSLoc::FREG, "Cannot store this type: %d", (int)mr[first].loc); + } + } } void RiscVRegCache::SetNativeRegValue(IRNativeReg nreg, uint32_t imm) { @@ -326,7 +426,7 @@ void RiscVRegCache::SetNativeRegValue(IRNativeReg nreg, uint32_t imm) { } void RiscVRegCache::StoreRegValue(IRReg mreg, uint32_t imm) { - _assert_(mreg != MIPS_REG_ZERO); + _assert_(IsValidGPRNoZero(mreg)); // Try to optimize using a different reg. RiscVReg storeReg = INVALID_REG; @@ -382,3 +482,14 @@ RiscVReg RiscVRegCache::RPtr(IRReg mipsReg) { return INVALID_REG; // BAAAD } } + +RiscVReg RiscVRegCache::F(IRReg mipsReg) { + _dbg_assert_(IsValidFPR(mipsReg)); + _dbg_assert_(mr[mipsReg + 32].loc == MIPSLoc::FREG); + if (mr[mipsReg + 32].loc == MIPSLoc::FREG) { + return (RiscVReg)mr[mipsReg + 32].nReg; + } else { + ERROR_LOG_REPORT(JIT, "Reg %i not in riscv reg", mipsReg); + return INVALID_REG; // BAAAD + } +} diff --git a/Core/MIPS/RiscV/RiscVRegCache.h b/Core/MIPS/RiscV/RiscVRegCache.h index ccf309207c..26cf0d9894 100644 --- a/Core/MIPS/RiscV/RiscVRegCache.h +++ b/Core/MIPS/RiscV/RiscVRegCache.h @@ -56,18 +56,29 @@ public: RiscVGen::RiscVReg MapGPR(IRReg reg, MIPSMap mapFlags = MIPSMap::INIT); RiscVGen::RiscVReg MapGPRAsPointer(IRReg reg); + void MapGPRDirtyIn(IRReg rd, IRReg rs, RiscVJitConstants::MapType type = RiscVJitConstants::MapType::AVOID_LOAD); + void MapGPRDirtyDirtyInIn(IRReg rd1, IRReg rd2, IRReg rs, IRReg rt, RiscVJitConstants::MapType type = RiscVJitConstants::MapType::AVOID_LOAD); + + // Returns a RISC-V register containing the requested MIPS register. + RiscVGen::RiscVReg MapFPR(IRReg reg, MIPSMap mapFlags = MIPSMap::INIT); + + void MapFPRDirtyInIn(IRReg rd, IRReg rs, IRReg rt, bool avoidLoad = true); + RiscVGen::RiscVReg MapFPRDirtyInTemp(IRReg rd, IRReg rs, bool avoidLoad = true); + void MapFPR4DirtyIn(IRReg rdbase, IRReg rsbase, bool avoidLoad = true); + RiscVGen::RiscVReg MapFPR4DirtyInTemp(IRReg rdbase, IRReg rsbase, bool avoidLoad = true); + bool IsNormalized32(IRReg reg); // Copies to another reg if specified, otherwise same reg. RiscVGen::RiscVReg Normalize32(IRReg reg, RiscVGen::RiscVReg destReg = RiscVGen::INVALID_REG); - void MapDirtyIn(IRReg rd, IRReg rs, RiscVJitConstants::MapType type = RiscVJitConstants::MapType::AVOID_LOAD); - void MapDirtyDirtyInIn(IRReg rd1, IRReg rd2, IRReg rs, IRReg rt, RiscVJitConstants::MapType type = RiscVJitConstants::MapType::AVOID_LOAD); + void FlushBeforeCall(); RiscVGen::RiscVReg GetAndLockTempR(); RiscVGen::RiscVReg R(IRReg preg); // Returns a cached register, while checking that it's NOT mapped as a pointer RiscVGen::RiscVReg RPtr(IRReg preg); // Returns a cached register, if it has been mapped as a pointer + RiscVGen::RiscVReg F(IRReg preg); // These are called once on startup to generate functions, that you should then call. void EmitLoadStaticRegisters(); @@ -88,6 +99,8 @@ private: RiscVGen::RiscVEmitter *emit_ = nullptr; enum { - NUM_RVREG = 32, + NUM_RVGPR = 32, + NUM_RVFPR = 32, + NUM_RVVPR = 32, }; }; diff --git a/Core/MIPS/RiscV/RiscVRegCacheFPU.cpp b/Core/MIPS/RiscV/RiscVRegCacheFPU.cpp deleted file mode 100644 index 9b544f450c..0000000000 --- a/Core/MIPS/RiscV/RiscVRegCacheFPU.cpp +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright (c) 2023- PPSSPP Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#ifndef offsetof -#include -#endif - -#include "Common/CPUDetect.h" -#include "Core/MIPS/IR/IRInst.h" -#include "Core/MIPS/IR/IRAnalysis.h" -#include "Core/MIPS/RiscV/RiscVRegCacheFPU.h" -#include "Core/MIPS/JitCommon/JitState.h" -#include "Core/Reporting.h" - -using namespace RiscVGen; -using namespace RiscVJitConstants; - -RiscVRegCacheFPU::RiscVRegCacheFPU(MIPSComp::JitOptions *jo) - : IRNativeRegCacheBase(jo) { - config_.totalNativeRegs = NUM_RVFPUREG; - // TODO: When using RISC-V V. - config_.mapUseVRegs = false; - config_.mapSIMD = false; -} - -void RiscVRegCacheFPU::Init(RiscVEmitter *emitter) { - emit_ = emitter; -} - -const int *RiscVRegCacheFPU::GetAllocationOrder(MIPSLoc type, int &count, int &base) const { - _assert_(type == MIPSLoc::FREG); - // F8 through F15 are used for compression, so they are great. - // TODO: Maybe we could remove some saved regs since we rarely need that many? Or maybe worth it? - static const int allocationOrder[] = { - F8, F9, F10, F11, F12, F13, F14, F15, - F0, F1, F2, F3, F4, F5, F6, F7, - F16, F17, F18, F19, F20, F21, F22, F23, F24, F25, F26, F27, F28, F29, F30, F31, - }; - - count = ARRAY_SIZE(allocationOrder); - base = F0; - return allocationOrder; -} - -RiscVReg RiscVRegCacheFPU::MapFPR(IRReg mipsReg, MIPSMap mapFlags) { - _dbg_assert_(IsValidFPR(mipsReg)); - _dbg_assert_(mr[mipsReg + 32].loc == MIPSLoc::MEM || mr[mipsReg + 32].loc == MIPSLoc::FREG); - - IRNativeReg nreg = MapNativeReg(MIPSLoc::FREG, mipsReg + 32, 1, mapFlags); - if (nreg != -1) - return (RiscVReg)(F0 + nreg); - return INVALID_REG; -} - -void RiscVRegCacheFPU::MapDirtyInIn(IRReg rd, IRReg rs, IRReg rt, bool avoidLoad) { - SpillLockFPR(rd, rs, rt); - bool load = !avoidLoad || (rd == rs || rd == rt); - MapFPR(rd, load ? MIPSMap::DIRTY : MIPSMap::NOINIT); - MapFPR(rt); - MapFPR(rs); - ReleaseSpillLockFPR(rd, rs, rt); -} - -RiscVReg RiscVRegCacheFPU::MapDirtyInTemp(IRReg rd, IRReg rs, bool avoidLoad) { - SpillLockFPR(rd, rs); - bool load = !avoidLoad || rd == rs; - MapFPR(rd, load ? MIPSMap::DIRTY : MIPSMap::NOINIT); - MapFPR(rs); - RiscVReg temp = (RiscVReg)(F0 + AllocateReg(MIPSLoc::FREG)); - ReleaseSpillLockFPR(rd, rs); - return temp; -} - -void RiscVRegCacheFPU::Map4DirtyIn(IRReg rdbase, IRReg rsbase, bool avoidLoad) { - for (int i = 0; i < 4; ++i) - SpillLockFPR(rdbase + i, rsbase + i); - bool load = !avoidLoad || (rdbase < rsbase + 4 && rdbase + 4 > rsbase); - for (int i = 0; i < 4; ++i) - MapFPR(rdbase + i, load ? MIPSMap::DIRTY : MIPSMap::NOINIT); - for (int i = 0; i < 4; ++i) - MapFPR(rsbase + i); - for (int i = 0; i < 4; ++i) - ReleaseSpillLockFPR(rdbase + i, rsbase + i); -} - -RiscVReg RiscVRegCacheFPU::Map4DirtyInTemp(IRReg rdbase, IRReg rsbase, bool avoidLoad) { - for (int i = 0; i < 4; ++i) - SpillLockFPR(rdbase + i, rsbase + i); - bool load = !avoidLoad || (rdbase < rsbase + 4 && rdbase + 4 > rsbase); - for (int i = 0; i < 4; ++i) - MapFPR(rdbase + i, load ? MIPSMap::DIRTY : MIPSMap::NOINIT); - for (int i = 0; i < 4; ++i) - MapFPR(rsbase + i); - RiscVReg temp = (RiscVReg)(F0 + AllocateReg(MIPSLoc::FREG)); - for (int i = 0; i < 4; ++i) - ReleaseSpillLockFPR(rdbase + i, rsbase + i); - return temp; -} - -void RiscVRegCacheFPU::LoadNativeReg(IRNativeReg nreg, IRReg first, int lanes) { - RiscVReg r = (RiscVReg)(F0 + nreg); - _dbg_assert_(r >= F0 && r <= F31); - // Multilane not yet supported. - _assert_(lanes == 1); - if (mr[first].loc == MIPSLoc::FREG) { - emit_->FL(32, r, CTXREG, GetMipsRegOffset(first)); - } else { - _assert_msg_(mr[first].loc == MIPSLoc::FREG, "Cannot store this type: %d", (int)mr[first].loc); - } -} - -void RiscVRegCacheFPU::StoreNativeReg(IRNativeReg nreg, IRReg first, int lanes) { - RiscVReg r = (RiscVReg)(F0 + nreg); - _dbg_assert_(r >= F0 && r <= F31); - // Multilane not yet supported. - _assert_(lanes == 1); - if (mr[first].loc == MIPSLoc::FREG) { - emit_->FS(32, r, CTXREG, GetMipsRegOffset(first)); - } else { - _assert_msg_(mr[first].loc == MIPSLoc::FREG, "Cannot store this type: %d", (int)mr[first].loc); - } -} - -void RiscVRegCacheFPU::SetNativeRegValue(IRNativeReg nreg, uint32_t imm) { - _assert_msg_(false, "Set float to imm is unsupported"); -} - -void RiscVRegCacheFPU::StoreRegValue(IRReg mreg, uint32_t imm) { - _assert_msg_(false, "Storing imms to floats is unsupported"); -} - -void RiscVRegCacheFPU::FlushBeforeCall() { - // These registers are not preserved by function calls. - for (int i = 0; i <= 7; ++i) { - FlushNativeReg(i); - } - for (int i = 10; i <= 17; ++i) { - FlushNativeReg(i); - } - for (int i = 28; i <= 31; ++i) { - FlushNativeReg(i); - } -} - -RiscVReg RiscVRegCacheFPU::R(IRReg mipsReg) { - _dbg_assert_(IsValidFPR(mipsReg)); - _dbg_assert_(mr[mipsReg + 32].loc == MIPSLoc::FREG); - if (mr[mipsReg + 32].loc == MIPSLoc::FREG) { - return (RiscVReg)(mr[mipsReg + 32].nReg + F0); - } else { - ERROR_LOG_REPORT(JIT, "Reg %i not in riscv reg", mipsReg); - return INVALID_REG; // BAAAD - } -} - -void RiscVRegCacheFPU::SetupInitialRegs() { - IRNativeRegCacheBase::SetupInitialRegs(); - - // TODO: Move to a shared cache? - mrInitial_[0].loc = MIPSLoc::MEM; -} diff --git a/Core/MIPS/RiscV/RiscVRegCacheFPU.h b/Core/MIPS/RiscV/RiscVRegCacheFPU.h deleted file mode 100644 index e651436b48..0000000000 --- a/Core/MIPS/RiscV/RiscVRegCacheFPU.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2023- PPSSPP Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#pragma once - -#include "Common/RiscVEmitter.h" -#include "Core/MIPS/MIPS.h" -#include "Core/MIPS/RiscV/RiscVRegCache.h" - -namespace MIPSComp { -struct JitOptions; -} - -class RiscVRegCacheFPU : public IRNativeRegCacheBase { -public: - RiscVRegCacheFPU(MIPSComp::JitOptions *jo); - - void Init(RiscVGen::RiscVEmitter *emitter); - - // Returns a RISC-V register containing the requested MIPS register. - RiscVGen::RiscVReg MapFPR(IRReg reg, MIPSMap mapFlags = MIPSMap::INIT); - - void MapDirtyInIn(IRReg rd, IRReg rs, IRReg rt, bool avoidLoad = true); - RiscVGen::RiscVReg MapDirtyInTemp(IRReg rd, IRReg rs, bool avoidLoad = true); - void Map4DirtyIn(IRReg rdbase, IRReg rsbase, bool avoidLoad = true); - RiscVGen::RiscVReg Map4DirtyInTemp(IRReg rdbase, IRReg rsbase, bool avoidLoad = true); - void FlushBeforeCall(); - - RiscVGen::RiscVReg R(IRReg preg); // Returns a cached register - -protected: - void SetupInitialRegs() override; - const int *GetAllocationOrder(MIPSLoc type, int &count, int &base) const override; - - void LoadNativeReg(IRNativeReg nreg, IRReg first, int lanes) override; - void StoreNativeReg(IRNativeReg nreg, IRReg first, int lanes) override; - void SetNativeRegValue(IRNativeReg nreg, uint32_t imm) override; - void StoreRegValue(IRReg mreg, uint32_t imm) override; - -private: - RiscVGen::RiscVEmitter *emit_ = nullptr; - - enum { - NUM_RVFPUREG = 32, - }; -};