diff --git a/rpcs3/Emu/CPU/CPUTranslator.cpp b/rpcs3/Emu/CPU/CPUTranslator.cpp index 8466443a4c..e0d1957ad9 100644 --- a/rpcs3/Emu/CPU/CPUTranslator.cpp +++ b/rpcs3/Emu/CPU/CPUTranslator.cpp @@ -371,23 +371,69 @@ void cpu_translator::replace_intrinsics(llvm::Function& f) { for (auto& bb : f) { - for (auto bit = bb.begin(); bit != bb.end();) + std::set names; + + using InstListType = llvm::BasicBlock::InstListType; + + std::function fix_funcs; + + fix_funcs = [&](InstListType::iterator inst_bit) { - if (auto ci = llvm::dyn_cast(&*bit)) + auto ci = llvm::dyn_cast(&*inst_bit); + + if (!ci) { - if (auto cf = ci->getCalledFunction()) + return std::next(inst_bit); + } + + const auto cf = ci->getCalledFunction(); + + if (!cf) + { + return std::next(inst_bit); + } + + std::string_view func_name{cf->getName().data(), cf->getName().size()}; + + const auto it = m_intrinsics.find(func_name); + + if (it == m_intrinsics.end()) + { + return std::next(inst_bit); + } + + if (names.contains(func_name)) + { + fmt::throw_exception("cpu_translator::replace_intrinsics(): Recursion detected at function '%s'!", func_name); + } + + names.emplace(func_name); + + m_ir->SetInsertPoint(ci); + auto result = it->second(ci); + auto end = m_ir->GetInsertPoint(); + + inst_bit->replaceAllUsesWith(result); + const auto next_it = inst_bit->eraseFromParent(); + + for (auto inner = ci->getNextNode(); inner && InstListType::iterator(inner) != end;) + { + if (auto it_ci = llvm::dyn_cast(&*inner)) { - if (auto it = m_intrinsics.find(std::string_view(cf->getName().data(), cf->getName().size())); it != m_intrinsics.end()) - { - m_ir->SetInsertPoint(ci); - ci->replaceAllUsesWith(it->second(ci)); - bit = ci->eraseFromParent(); - continue; - } + fix_funcs(InstListType::iterator(inner)); + } + else + { + inner = inner->getNextNode(); } } - ++bit; + ensure(names.erase(func_name)); + return next_it; + }; + + for (auto bit = bb.begin(); bit != bb.end(); bit = fix_funcs(bit)) + { } } }