diff --git a/rpcs3/Emu/Cell/PPUInterpreter.cpp b/rpcs3/Emu/Cell/PPUInterpreter.cpp index edaa3a6126..f08246d871 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.cpp +++ b/rpcs3/Emu/Cell/PPUInterpreter.cpp @@ -81,6 +81,59 @@ inline void ppu_fpcc_set(ppu_thread& ppu, const T& a, const T& b, const bool rc, } } +// Validate read data in case does not match reservation +template +FORCE_INLINE auto ppu_feed_data(ppu_thread& ppu, u64 addr) +{ + static_assert(sizeof(T) <= 128, "Incompatible type-size, break down into smaller loads"); + + auto value = vm::_ref(vm::cast(addr, HERE)); + + if (!ppu.use_full_rdata) + { + return value; + } + + const u32 raddr = ppu.raddr; + + if (addr / 128 > raddr / 128 || (addr + sizeof(T) - 1) / 128 < raddr / 128) + { + // Out of range or reservation does not exist + return value; + } + + if (sizeof(T) == 1 || addr / 128 == (addr + sizeof(T) - 1) / 128) + { + // Optimized comparison + if (std::memcmp(&value, &ppu.rdata[addr & 127], sizeof(T))) + { + // Reservation was lost + ppu.raddr = 0; + } + } + else + { + alignas(16) std::byte buffer[sizeof(T)]; + std::memcpy(buffer, &value, sizeof(value)); // Put in memory explicitly (ensure the compiler won't do it beforehand) + + const std::byte* src; + u32 size; + u32 offs = 0; + + if (raddr / 128 == addr / 128) + src = &ppu.rdata[addr & 127], size = std::min(128 - (addr % 128), sizeof(T)); + else + src = &ppu.rdata[0], size = (addr + u32{sizeof(T)}) % 127, offs = sizeof(T) - size; + + if (std::memcmp(buffer + offs, src, size)) + { + ppu.raddr = 0; + } + } + + return value; +} + // Compare 16 packed unsigned bytes (greater than) inline __m128i sse_cmpgt_epu8(__m128i A, __m128i B) { @@ -3375,14 +3428,14 @@ bool ppu_interpreter::LWARX(ppu_thread& ppu, ppu_opcode_t op) bool ppu_interpreter::LDX(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]; - ppu.gpr[op.rd] = vm::read64(vm::cast(addr, HERE)); + ppu.gpr[op.rd] = ppu_feed_data(ppu, addr); return true; } bool ppu_interpreter::LWZX(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]; - ppu.gpr[op.rd] = vm::read32(vm::cast(addr, HERE)); + ppu.gpr[op.rd] = ppu_feed_data(ppu, addr); return true; } @@ -3453,7 +3506,7 @@ bool ppu_interpreter::SUBF(ppu_thread& ppu, ppu_opcode_t op) bool ppu_interpreter::LDUX(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = ppu.gpr[op.ra] + ppu.gpr[op.rb]; - ppu.gpr[op.rd] = vm::read64(vm::cast(addr, HERE)); + ppu.gpr[op.rd] = ppu_feed_data(ppu, addr); ppu.gpr[op.ra] = addr; return true; } @@ -3466,7 +3519,7 @@ bool ppu_interpreter::DCBST(ppu_thread& ppu, ppu_opcode_t op) bool ppu_interpreter::LWZUX(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = ppu.gpr[op.ra] + ppu.gpr[op.rb]; - ppu.gpr[op.rd] = vm::read32(vm::cast(addr, HERE)); + ppu.gpr[op.rd] = ppu_feed_data(ppu, addr); ppu.gpr[op.ra] = addr; return true; } @@ -3539,14 +3592,14 @@ bool ppu_interpreter::DCBF(ppu_thread& ppu, ppu_opcode_t op) bool ppu_interpreter::LBZX(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]; - ppu.gpr[op.rd] = vm::read8(vm::cast(addr, HERE)); + ppu.gpr[op.rd] = ppu_feed_data(ppu, addr); return true; } bool ppu_interpreter::LVX(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = (op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]) & ~0xfull; - ppu.vr[op.vd] = vm::_ref(vm::cast(addr, HERE)); + ppu.vr[op.vd] = ppu_feed_data(ppu, addr); return true; } @@ -3562,7 +3615,7 @@ bool ppu_interpreter::NEG(ppu_thread& ppu, ppu_opcode_t op) bool ppu_interpreter::LBZUX(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = ppu.gpr[op.ra] + ppu.gpr[op.rb]; - ppu.gpr[op.rd] = vm::read8(vm::cast(addr, HERE)); + ppu.gpr[op.rd] = ppu_feed_data(ppu, addr); ppu.gpr[op.ra] = addr; return true; } @@ -3825,7 +3878,7 @@ bool ppu_interpreter::DCBT(ppu_thread& ppu, ppu_opcode_t op) bool ppu_interpreter::LHZX(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]; - ppu.gpr[op.rd] = vm::read16(vm::cast(addr, HERE)); + ppu.gpr[op.rd] = ppu_feed_data(ppu, addr); return true; } @@ -3844,7 +3897,7 @@ bool ppu_interpreter::ECIWX(ppu_thread& ppu, ppu_opcode_t op) bool ppu_interpreter::LHZUX(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]; - ppu.gpr[op.rd] = vm::read16(vm::cast(addr, HERE)); + ppu.gpr[op.rd] = ppu_feed_data(ppu, addr); ppu.gpr[op.ra] = addr; return true; } @@ -3878,7 +3931,7 @@ bool ppu_interpreter::MFSPR(ppu_thread& ppu, ppu_opcode_t op) bool ppu_interpreter::LWAX(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]; - ppu.gpr[op.rd] = static_cast(vm::read32(vm::cast(addr, HERE))); + ppu.gpr[op.rd] = ppu_feed_data(ppu, addr); return true; } @@ -3890,14 +3943,14 @@ bool ppu_interpreter::DST(ppu_thread& ppu, ppu_opcode_t op) bool ppu_interpreter::LHAX(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]; - ppu.gpr[op.rd] = static_cast(vm::read16(vm::cast(addr, HERE))); + ppu.gpr[op.rd] = ppu_feed_data(ppu, addr); return true; } bool ppu_interpreter::LVXL(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = (op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]) & ~0xfull; - ppu.vr[op.vd] = vm::_ref(vm::cast(addr, HERE)); + ppu.vr[op.vd] = ppu_feed_data(ppu, addr); return true; } @@ -3918,7 +3971,7 @@ bool ppu_interpreter::MFTB(ppu_thread& ppu, ppu_opcode_t op) bool ppu_interpreter::LWAUX(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]; - ppu.gpr[op.rd] = static_cast(vm::read32(vm::cast(addr, HERE))); + ppu.gpr[op.rd] = ppu_feed_data(ppu, addr); ppu.gpr[op.ra] = addr; return true; } @@ -3931,7 +3984,7 @@ bool ppu_interpreter::DSTST(ppu_thread& ppu, ppu_opcode_t op) bool ppu_interpreter::LHAUX(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]; - ppu.gpr[op.rd] = static_cast(vm::read16(vm::cast(addr, HERE))); + ppu.gpr[op.rd] = ppu_feed_data(ppu, addr); ppu.gpr[op.ra] = addr; return true; } @@ -4065,7 +4118,7 @@ bool ppu_interpreter::LVLX(ppu_thread& ppu, ppu_opcode_t op) bool ppu_interpreter::LDBRX(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]; - ppu.gpr[op.rd] = vm::_ref>(vm::cast(addr, HERE)); + ppu.gpr[op.rd] = ppu_feed_data>(ppu, addr); return true; } @@ -4075,14 +4128,14 @@ bool ppu_interpreter::LSWX(ppu_thread& ppu, ppu_opcode_t op) u32 count = ppu.xer.cnt & 0x7f; for (; count >= 4; count -= 4, addr += 4, op.rd = (op.rd + 1) & 31) { - ppu.gpr[op.rd] = vm::_ref(vm::cast(addr, HERE)); + ppu.gpr[op.rd] = ppu_feed_data(ppu, addr); } if (count) { u32 value = 0; for (u32 byte = 0; byte < count; byte++) { - u32 byte_value = vm::_ref(vm::cast(addr + byte, HERE)); + u32 byte_value = ppu_feed_data(ppu, addr + byte); value |= byte_value << ((3 ^ byte) * 8); } ppu.gpr[op.rd] = value; @@ -4093,14 +4146,14 @@ bool ppu_interpreter::LSWX(ppu_thread& ppu, ppu_opcode_t op) bool ppu_interpreter::LWBRX(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]; - ppu.gpr[op.rd] = vm::_ref>(vm::cast(addr, HERE)); + ppu.gpr[op.rd] = ppu_feed_data>(ppu, addr); return true; } bool ppu_interpreter::LFSX(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]; - ppu.fpr[op.frd] = vm::_ref(vm::cast(addr, HERE)); + ppu.fpr[op.frd] = ppu_feed_data(ppu, addr); return true; } @@ -4136,7 +4189,7 @@ bool ppu_interpreter::LSWI(ppu_thread& ppu, ppu_opcode_t op) { if (N > 3) { - ppu.gpr[reg] = vm::read32(vm::cast(addr, HERE)); + ppu.gpr[reg] = ppu_feed_data(ppu, addr); addr += 4; N -= 4; } @@ -4147,7 +4200,7 @@ bool ppu_interpreter::LSWI(ppu_thread& ppu, ppu_opcode_t op) while (N > 0) { N = N - 1; - buf |= vm::read8(vm::cast(addr, HERE)) << (i * 8); + buf |= ppu_feed_data(ppu, addr) << (i * 8); addr++; i--; } @@ -4161,7 +4214,7 @@ bool ppu_interpreter::LSWI(ppu_thread& ppu, ppu_opcode_t op) bool ppu_interpreter::LFSUX(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = ppu.gpr[op.ra] + ppu.gpr[op.rb]; - ppu.fpr[op.frd] = vm::_ref(vm::cast(addr, HERE)); + ppu.fpr[op.frd] = ppu_feed_data(ppu, addr); ppu.gpr[op.ra] = addr; return true; } @@ -4175,14 +4228,14 @@ bool ppu_interpreter::SYNC(ppu_thread& ppu, ppu_opcode_t op) bool ppu_interpreter::LFDX(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]; - ppu.fpr[op.frd] = vm::_ref(vm::cast(addr, HERE)); + ppu.fpr[op.frd] = ppu_feed_data(ppu, addr); return true; } bool ppu_interpreter::LFDUX(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = ppu.gpr[op.ra] + ppu.gpr[op.rb]; - ppu.fpr[op.frd] = vm::_ref(vm::cast(addr, HERE)); + ppu.fpr[op.frd] = ppu_feed_data(ppu, addr); ppu.gpr[op.ra] = addr; return true; } @@ -4303,7 +4356,7 @@ bool ppu_interpreter::LVLXL(ppu_thread& ppu, ppu_opcode_t op) bool ppu_interpreter::LHBRX(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]; - ppu.gpr[op.rd] = vm::_ref>(vm::cast(addr, HERE)); + ppu.gpr[op.rd] = ppu_feed_data>(ppu, addr); return true; } @@ -4451,14 +4504,14 @@ bool ppu_interpreter::DCBZ(ppu_thread& ppu, ppu_opcode_t op) bool ppu_interpreter::LWZ(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = op.ra ? ppu.gpr[op.ra] + op.simm16 : op.simm16; - ppu.gpr[op.rd] = vm::read32(vm::cast(addr, HERE)); + ppu.gpr[op.rd] = ppu_feed_data(ppu, addr); return true; } bool ppu_interpreter::LWZU(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = ppu.gpr[op.ra] + op.simm16; - ppu.gpr[op.rd] = vm::read32(vm::cast(addr, HERE)); + ppu.gpr[op.rd] = ppu_feed_data(ppu, addr); ppu.gpr[op.ra] = addr; return true; } @@ -4466,14 +4519,14 @@ bool ppu_interpreter::LWZU(ppu_thread& ppu, ppu_opcode_t op) bool ppu_interpreter::LBZ(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = op.ra ? ppu.gpr[op.ra] + op.simm16 : op.simm16; - ppu.gpr[op.rd] = vm::read8(vm::cast(addr, HERE)); + ppu.gpr[op.rd] = ppu_feed_data(ppu, addr); return true; } bool ppu_interpreter::LBZU(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = ppu.gpr[op.ra] + op.simm16; - ppu.gpr[op.rd] = vm::read8(vm::cast(addr, HERE)); + ppu.gpr[op.rd] = ppu_feed_data(ppu, addr); ppu.gpr[op.ra] = addr; return true; } @@ -4519,14 +4572,14 @@ bool ppu_interpreter::STBU(ppu_thread& ppu, ppu_opcode_t op) bool ppu_interpreter::LHZ(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = op.ra ? ppu.gpr[op.ra] + op.simm16 : op.simm16; - ppu.gpr[op.rd] = vm::read16(vm::cast(addr, HERE)); + ppu.gpr[op.rd] = ppu_feed_data(ppu, addr); return true; } bool ppu_interpreter::LHZU(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = ppu.gpr[op.ra] + op.simm16; - ppu.gpr[op.rd] = vm::read16(vm::cast(addr, HERE)); + ppu.gpr[op.rd] = ppu_feed_data(ppu, addr); ppu.gpr[op.ra] = addr; return true; } @@ -4534,14 +4587,14 @@ bool ppu_interpreter::LHZU(ppu_thread& ppu, ppu_opcode_t op) bool ppu_interpreter::LHA(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = op.ra ? ppu.gpr[op.ra] + op.simm16 : op.simm16; - ppu.gpr[op.rd] = static_cast(vm::read16(vm::cast(addr, HERE))); + ppu.gpr[op.rd] = ppu_feed_data(ppu, addr); return true; } bool ppu_interpreter::LHAU(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = ppu.gpr[op.ra] + op.simm16; - ppu.gpr[op.rd] = static_cast(vm::read16(vm::cast(addr, HERE))); + ppu.gpr[op.rd] = ppu_feed_data(ppu, addr); ppu.gpr[op.ra] = addr; return true; } @@ -4566,7 +4619,7 @@ bool ppu_interpreter::LMW(ppu_thread& ppu, ppu_opcode_t op) u64 addr = op.ra ? ppu.gpr[op.ra] + op.simm16 : op.simm16; for (u32 i = op.rd; i<32; ++i, addr += 4) { - ppu.gpr[i] = vm::read32(vm::cast(addr, HERE)); + ppu.gpr[i] = ppu_feed_data(ppu, addr); } return true; } @@ -4584,14 +4637,14 @@ bool ppu_interpreter::STMW(ppu_thread& ppu, ppu_opcode_t op) bool ppu_interpreter::LFS(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = op.ra ? ppu.gpr[op.ra] + op.simm16 : op.simm16; - ppu.fpr[op.frd] = vm::_ref(vm::cast(addr, HERE)); + ppu.fpr[op.frd] = ppu_feed_data(ppu, addr); return true; } bool ppu_interpreter::LFSU(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = ppu.gpr[op.ra] + op.simm16; - ppu.fpr[op.frd] = vm::_ref(vm::cast(addr, HERE)); + ppu.fpr[op.frd] = ppu_feed_data(ppu, addr); ppu.gpr[op.ra] = addr; return true; } @@ -4599,14 +4652,14 @@ bool ppu_interpreter::LFSU(ppu_thread& ppu, ppu_opcode_t op) bool ppu_interpreter::LFD(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = op.ra ? ppu.gpr[op.ra] + op.simm16 : op.simm16; - ppu.fpr[op.frd] = vm::_ref(vm::cast(addr, HERE)); + ppu.fpr[op.frd] = ppu_feed_data(ppu, addr); return true; } bool ppu_interpreter::LFDU(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = ppu.gpr[op.ra] + op.simm16; - ppu.fpr[op.frd] = vm::_ref(vm::cast(addr, HERE)); + ppu.fpr[op.frd] = ppu_feed_data(ppu, addr); ppu.gpr[op.ra] = addr; return true; } @@ -4644,14 +4697,14 @@ bool ppu_interpreter::STFDU(ppu_thread& ppu, ppu_opcode_t op) bool ppu_interpreter::LD(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = (op.simm16 & ~3) + (op.ra ? ppu.gpr[op.ra] : 0); - ppu.gpr[op.rd] = vm::read64(vm::cast(addr, HERE)); + ppu.gpr[op.rd] = ppu_feed_data(ppu, addr); return true; } bool ppu_interpreter::LDU(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = ppu.gpr[op.ra] + (op.simm16 & ~3); - ppu.gpr[op.rd] = vm::read64(vm::cast(addr, HERE)); + ppu.gpr[op.rd] = ppu_feed_data(ppu, addr); ppu.gpr[op.ra] = addr; return true; } @@ -4659,7 +4712,7 @@ bool ppu_interpreter::LDU(ppu_thread& ppu, ppu_opcode_t op) bool ppu_interpreter::LWA(ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = (op.simm16 & ~3) + (op.ra ? ppu.gpr[op.ra] : 0); - ppu.gpr[op.rd] = static_cast(vm::read32(vm::cast(addr, HERE))); + ppu.gpr[op.rd] = ppu_feed_data(ppu, addr); return true; } diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index b8adf620b9..6b88c9504d 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -174,6 +174,43 @@ void ppu_recompiler_fallback(ppu_thread& ppu) } } +void ppu_reservation_fallback(ppu_thread& ppu) +{ + const auto& table = g_ppu_interpreter_fast.get_table(); + + const u32 min_hle = ppu_function_manager::addr ? ppu_function_manager::addr : UINT32_MAX; + const u32 max_hle = min_hle + ppu_function_manager::get().size() * 8 - 1; + + while (true) + { + // Run instructions in interpreter + const u32 op = vm::read32(ppu.cia); + + if (op == ppu.cia && ppu.cia >= min_hle && ppu.cia <= max_hle) + { + // HLE function + // ppu.raddr = 0; + return; + } + + if (table[ppu_decode(op)](ppu, {op})) [[likely]] + { + ppu.cia += 4; + } + + if (!ppu.raddr || !ppu.use_full_rdata) + { + // We've escaped from reservation, return. + return; + } + + if (ppu.test_stopped()) + { + return; + } + } +} + static std::unordered_map* s_ppu_toc; static bool ppu_check_toc(ppu_thread& ppu, ppu_opcode_t op) @@ -1770,6 +1807,7 @@ extern void ppu_initialize(const ppu_module& info) { "__stvrx", s_use_ssse3 ? reinterpret_cast(sse_cellbe_stvrx) : reinterpret_cast(sse_cellbe_stvrx_v0) }, { "__dcbz", reinterpret_cast(+[](u32 addr){ alignas(64) static constexpr u8 z[128]{}; do_cell_atomic_128_store(addr, z); }) }, { "__resupdate", reinterpret_cast(vm::reservation_update) }, + { "__resinterp", reinterpret_cast(ppu_reservation_fallback) }, }; for (u64 index = 0; index < 1024; index++) @@ -2052,7 +2090,7 @@ extern void ppu_initialize(const ppu_module& info) { settings += ppu_settings::accurate_cache_line_stores; } - if (g_cfg.core.ppu_128_reservations_loop_max_length > 0) + if (g_cfg.core.ppu_128_reservations_loop_max_length) { settings += ppu_settings::reservations_128_byte; } diff --git a/rpcs3/Emu/Cell/PPUTranslator.cpp b/rpcs3/Emu/Cell/PPUTranslator.cpp index 796d167e64..68631fdf8d 100644 --- a/rpcs3/Emu/Cell/PPUTranslator.cpp +++ b/rpcs3/Emu/Cell/PPUTranslator.cpp @@ -2527,10 +2527,13 @@ void PPUTranslator::MFOCRF(ppu_opcode_t op) void PPUTranslator::LWARX(ppu_opcode_t op) { - if (g_cfg.core.ppu_128_reservations_loop_max_length > 0) + if (g_cfg.core.ppu_128_reservations_loop_max_length) { - // CIA will be used in lwarx handler - m_ir->CreateStore(Trunc(GetAddr(), GetType()), m_ir->CreateStructGEP(nullptr, m_thread, static_cast(&m_cia - m_locals)), true); + RegStore(Trunc(GetAddr()), m_cia); + FlushRegisters(); + Call(GetType(), "__resinterp", m_thread)->setTailCallKind(llvm::CallInst::TCK_Tail); + m_ir->CreateRetVoid(); + return; } SetGpr(op.rd, Call(GetType(), "__lwarx", m_thread, op.ra ? m_ir->CreateAdd(GetGpr(op.ra), GetGpr(op.rb)) : GetGpr(op.rb))); @@ -2669,10 +2672,13 @@ void PPUTranslator::MULHW(ppu_opcode_t op) void PPUTranslator::LDARX(ppu_opcode_t op) { - if (g_cfg.core.ppu_128_reservations_loop_max_length > 0) + if (g_cfg.core.ppu_128_reservations_loop_max_length) { - // CIA will be used in ldarx handler - m_ir->CreateStore(Trunc(GetAddr(), GetType()), m_ir->CreateStructGEP(nullptr, m_thread, static_cast(&m_cia - m_locals)), true); + RegStore(Trunc(GetAddr()), m_cia); + FlushRegisters(); + Call(GetType(), "__resinterp", m_thread)->setTailCallKind(llvm::CallInst::TCK_Tail); + m_ir->CreateRetVoid(); + return; } SetGpr(op.rd, Call(GetType(), "__ldarx", m_thread, op.ra ? m_ir->CreateAdd(GetGpr(op.ra), GetGpr(op.rb)) : GetGpr(op.rb)));