diff --git a/rpcs3/Emu/Cell/PPUTranslator.cpp b/rpcs3/Emu/Cell/PPUTranslator.cpp index c0a55da26de5..6e2a1db00a93 100644 --- a/rpcs3/Emu/Cell/PPUTranslator.cpp +++ b/rpcs3/Emu/Cell/PPUTranslator.cpp @@ -266,7 +266,7 @@ Function* PPUTranslator::Translate(const ppu_function& info) if (!m_ir->GetInsertBlock()->getTerminator()) { FlushRegisters(); - CallFunction(m_addr); + CallFunction(m_addr, nullptr, m_ir->GetInsertBlock()); } } @@ -354,7 +354,7 @@ Value* PPUTranslator::RotateLeft(Value* arg, Value* n) return m_ir->CreateOr(m_ir->CreateShl(arg, m_ir->CreateAnd(n, mask)), m_ir->CreateLShr(arg, m_ir->CreateAnd(m_ir->CreateNeg(n), mask))); } -void PPUTranslator::CallFunction(u64 target, Value* indirect) +void PPUTranslator::CallFunction(u64 target, Value* indirect, BasicBlock* prev_block) { const auto type = m_function->getFunctionType(); const auto block = m_ir->GetInsertBlock(); @@ -372,13 +372,19 @@ void PPUTranslator::CallFunction(u64 target, Value* indirect) if (_target >= caddr && _target <= cend) { - std::unordered_set passed_targets{_target}; + std::unordered_set passed_targets; u32 target_last = _target; // Try to follow unconditional branches as long as there is no infinite loop - while (target_last != _target) + while (target_last != m_addr + base) { + if (passed_targets.empty()) + { + passed_targets.emplace(_target); + passed_targets.emplace(m_addr + base); + } + const ppu_opcode_t op{*ensure(m_info.get_ptr(target_last))}; const ppu_itype::type itype = g_ppu_itype.decode(op.opcode); @@ -401,11 +407,25 @@ void PPUTranslator::CallFunction(u64 target, Value* indirect) // Odd destination } - else if (itype == ppu_itype::BCLR && (op.bo & 0x14) == 0x14 && !op.lk) + else if (itype == ppu_itype::BCLR && (op.bo & 0x14) == 0x14 && !op.lk && (prev_block || m_lr)) { // Special case: empty function // In this case the branch can be treated as BCLR because previous CIA does not matter - indirect = RegLoad(m_lr); + indirect = m_lr; + + if (!indirect) + { + if (block != prev_block) + { + // Emit register load in the beginning of the common block + m_ir->SetInsertPoint(prev_block, prev_block->getFirstInsertionPt()); + } + + indirect = RegLoad(m_lr); + + // Restore current insert point + m_ir->SetInsertPoint(block); + } } break; @@ -629,7 +649,7 @@ Value* PPUTranslator::Trunc(Value* value, Type* type) return type != value->getType() ? m_ir->CreateTrunc(value, type) : value; } -void PPUTranslator::UseCondition(MDNode* hint, Value* cond) +void PPUTranslator::UseCondition(MDNode* hint, Value* cond, BasicBlock* prev_block) { FlushRegisters(); @@ -639,7 +659,7 @@ void PPUTranslator::UseCondition(MDNode* hint, Value* cond) const auto next = BasicBlock::Create(m_context, "__next", m_function); m_ir->CreateCondBr(cond, local, next, hint); m_ir->SetInsertPoint(next); - CallFunction(m_addr + 4); + CallFunction(m_addr + 4, nullptr, prev_block); m_ir->SetInsertPoint(local); } } @@ -2024,6 +2044,8 @@ void PPUTranslator::BC(ppu_opcode_t op) const s32 bt14 = op.bt14; // Workaround for VS 16.5 const u64 target = (op.aa ? 0 : m_addr) + bt14; + const auto block = m_ir->GetInsertBlock(); + if (op.aa && m_reloc) { CompilationError("Branch with absolute address"); @@ -2031,12 +2053,13 @@ void PPUTranslator::BC(ppu_opcode_t op) if (op.lk) { - m_ir->CreateStore(GetAddr(+4), m_ir->CreateStructGEP(m_thread_type, m_thread, static_cast(&m_lr - m_locals))); + m_lr = GetAddr(+4); + m_ir->CreateStore(m_lr, m_ir->CreateStructGEP(m_thread_type, m_thread, static_cast(&m_lr - m_locals))); } - UseCondition(CheckBranchProbability(op.bo), CheckBranchCondition(op.bo, op.bi)); + UseCondition(CheckBranchProbability(op.bo), CheckBranchCondition(op.bo, op.bi), block); - CallFunction(target); + CallFunction(target, nullptr, block); } void PPUTranslator::SC(ppu_opcode_t op) @@ -2074,6 +2097,8 @@ void PPUTranslator::B(ppu_opcode_t op) const s32 bt24 = op.bt24; // Workaround for VS 16.5 const u64 target = (op.aa ? 0 : m_addr) + bt24; + const auto block = m_ir->GetInsertBlock(); + if (op.aa && m_reloc) { CompilationError("Branch with absolute address"); @@ -2085,7 +2110,7 @@ void PPUTranslator::B(ppu_opcode_t op) } FlushRegisters(); - CallFunction(target); + CallFunction(target, nullptr, block); } void PPUTranslator::MCRF(ppu_opcode_t op) @@ -2103,7 +2128,8 @@ void PPUTranslator::BCLR(ppu_opcode_t op) if (op.lk) { - m_ir->CreateStore(GetAddr(+4), m_ir->CreateStructGEP(m_thread_type, m_thread, static_cast(&m_lr - m_locals))); + m_lr = GetAddr(+4); + m_ir->CreateStore(m_lr, m_ir->CreateStructGEP(m_thread_type, m_thread, static_cast(&m_lr - m_locals))); } UseCondition(CheckBranchProbability(op.bo), CheckBranchCondition(op.bo, op.bi)); @@ -2166,7 +2192,8 @@ void PPUTranslator::BCCTR(ppu_opcode_t op) if (op.lk) { - m_ir->CreateStore(GetAddr(+4), m_ir->CreateStructGEP(m_thread_type, m_thread, static_cast(&m_lr - m_locals))); + m_lr = GetAddr(+4); + m_ir->CreateStore(m_lr, m_ir->CreateStructGEP(m_thread_type, m_thread, static_cast(&m_lr - m_locals))); } UseCondition(CheckBranchProbability(op.bo | 0x4), CheckBranchCondition(op.bo | 0x4, op.bi)); diff --git a/rpcs3/Emu/Cell/PPUTranslator.h b/rpcs3/Emu/Cell/PPUTranslator.h index d72dc1de20c7..8b357dffbcae 100644 --- a/rpcs3/Emu/Cell/PPUTranslator.h +++ b/rpcs3/Emu/Cell/PPUTranslator.h @@ -148,7 +148,7 @@ class PPUTranslator final : public cpu_translator llvm::Value* RotateLeft(llvm::Value* arg, llvm::Value* n); // Emit function call - void CallFunction(u64 target, llvm::Value* indirect = nullptr); + void CallFunction(u64 target, llvm::Value* indirect = nullptr, llvm::BasicBlock* prev_block = nullptr); // Initialize global for writing llvm::Value* RegInit(llvm::Value*& local); @@ -292,7 +292,7 @@ class PPUTranslator final : public cpu_translator llvm::MDNode* CheckBranchProbability(u32 bo); // Branch to next instruction if condition failed, never branch on nullptr - void UseCondition(llvm::MDNode* hint, llvm::Value* = nullptr); + void UseCondition(llvm::MDNode* hint, llvm::Value* = nullptr, llvm::BasicBlock* prev_block = nullptr); // Get memory pointer llvm::Value* GetMemory(llvm::Value* addr);