mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-16 11:48:36 +12:00
SPU LLVM: improve codegen in loops
Use a trick in check_state to improve LICM pass.
This commit is contained in:
parent
e09c6ea4b4
commit
1294e0d189
1 changed files with 53 additions and 5 deletions
|
@ -2144,6 +2144,9 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
|
||||||
llvm::GlobalVariable* m_scale_float_to{};
|
llvm::GlobalVariable* m_scale_float_to{};
|
||||||
llvm::GlobalVariable* m_scale_to_float{};
|
llvm::GlobalVariable* m_scale_to_float{};
|
||||||
|
|
||||||
|
// Helper for check_state
|
||||||
|
llvm::GlobalVariable* m_fake_global1{};
|
||||||
|
|
||||||
llvm::MDNode* m_md_unlikely;
|
llvm::MDNode* m_md_unlikely;
|
||||||
llvm::MDNode* m_md_likely;
|
llvm::MDNode* m_md_likely;
|
||||||
|
|
||||||
|
@ -2998,12 +3001,13 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
|
||||||
const auto _body = llvm::BasicBlock::Create(m_context, "", m_function);
|
const auto _body = llvm::BasicBlock::Create(m_context, "", m_function);
|
||||||
const auto check = llvm::BasicBlock::Create(m_context, "", m_function);
|
const auto check = llvm::BasicBlock::Create(m_context, "", m_function);
|
||||||
const auto stop = llvm::BasicBlock::Create(m_context, "", m_function);
|
const auto stop = llvm::BasicBlock::Create(m_context, "", m_function);
|
||||||
m_ir->CreateCondBr(m_ir->CreateICmpEQ(m_ir->CreateLoad(pstate), m_ir->getInt32(0)), _body, check, m_md_likely);
|
m_ir->CreateCondBr(m_ir->CreateICmpEQ(m_ir->CreateLoad(pstate, true), m_ir->getInt32(0)), _body, check, m_md_likely);
|
||||||
m_ir->SetInsertPoint(check);
|
m_ir->SetInsertPoint(check);
|
||||||
m_ir->CreateStore(m_ir->getInt32(addr), spu_ptr<u32>(&spu_thread::pc));
|
m_ir->CreateStore(m_ir->getInt32(addr), spu_ptr<u32>(&spu_thread::pc));
|
||||||
m_ir->CreateCondBr(call(&exec_check_state, m_thread), stop, _body, m_md_unlikely);
|
m_ir->CreateCondBr(m_ir->CreateLoad(m_fake_global1, true), stop, _body, m_md_unlikely);
|
||||||
m_ir->SetInsertPoint(stop);
|
m_ir->SetInsertPoint(stop);
|
||||||
m_ir->CreateRetVoid();
|
m_ir->CreateStore(m_ir->getFalse(), m_fake_global1, true);
|
||||||
|
m_ir->CreateBr(_body);
|
||||||
m_ir->SetInsertPoint(_body);
|
m_ir->SetInsertPoint(_body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3164,6 +3168,9 @@ public:
|
||||||
IRBuilder<> irb(m_context);
|
IRBuilder<> irb(m_context);
|
||||||
m_ir = &irb;
|
m_ir = &irb;
|
||||||
|
|
||||||
|
// Helper for check_state. Used to not interfere with LICM pass.
|
||||||
|
m_fake_global1 = new llvm::GlobalVariable(*m_module, get_type<bool>(), false, llvm::GlobalValue::InternalLinkage, m_ir->getFalse());
|
||||||
|
|
||||||
// Add entry function (contains only state/code check)
|
// Add entry function (contains only state/code check)
|
||||||
const auto main_func = llvm::cast<llvm::Function>(m_module->getOrInsertFunction(hash, get_ftype<void, u8*, u8*, u8*>()).getCallee());
|
const auto main_func = llvm::cast<llvm::Function>(m_module->getOrInsertFunction(hash, get_ftype<void, u8*, u8*, u8*>()).getCallee());
|
||||||
const auto main_arg2 = &*(main_func->arg_begin() + 2);
|
const auto main_arg2 = &*(main_func->arg_begin() + 2);
|
||||||
|
@ -3547,13 +3554,54 @@ public:
|
||||||
pm.add(createCFGSimplificationPass());
|
pm.add(createCFGSimplificationPass());
|
||||||
pm.add(createNewGVNPass());
|
pm.add(createNewGVNPass());
|
||||||
pm.add(createDeadStoreEliminationPass());
|
pm.add(createDeadStoreEliminationPass());
|
||||||
pm.add(createLoopVersioningLICMPass());
|
pm.add(createLICMPass());
|
||||||
pm.add(createAggressiveDCEPass());
|
pm.add(createAggressiveDCEPass());
|
||||||
//pm.add(createLintPass()); // Check
|
//pm.add(createLintPass()); // Check
|
||||||
|
|
||||||
for (const auto& func : m_functions)
|
for (const auto& func : m_functions)
|
||||||
{
|
{
|
||||||
pm.run(*func.second.func);
|
const auto f = func.second.func;
|
||||||
|
pm.run(*f);
|
||||||
|
|
||||||
|
for (auto& bb : *f)
|
||||||
|
{
|
||||||
|
for (auto& i : bb)
|
||||||
|
{
|
||||||
|
// Replace volatile fake load with check_state call
|
||||||
|
if (auto li = dyn_cast<LoadInst>(&i); li && li->getOperand(0) == m_fake_global1)
|
||||||
|
{
|
||||||
|
m_ir->SetInsertPoint(bb.getTerminator());
|
||||||
|
li->replaceAllUsesWith(call(&exec_check_state, &*f->arg_begin()));
|
||||||
|
li->eraseFromParent();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace volatile fake store with return
|
||||||
|
if (auto si = dyn_cast<StoreInst>(&i); si && si->getOperand(1) == m_fake_global1)
|
||||||
|
{
|
||||||
|
const auto br = bb.getTerminator();
|
||||||
|
|
||||||
|
for (auto& j : *br->getSuccessor(0))
|
||||||
|
{
|
||||||
|
// Cleanup PHI nodes if exist
|
||||||
|
if (auto phi = dyn_cast<PHINode>(&j))
|
||||||
|
{
|
||||||
|
phi->removeIncomingValue(&bb, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_ir->SetInsertPoint(bb.getTerminator());
|
||||||
|
m_ir->CreateRetVoid();
|
||||||
|
si->eraseFromParent();
|
||||||
|
br->eraseFromParent();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear context (TODO)
|
// Clear context (TODO)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue