PPU: block info fix

This commit is contained in:
Nekotekina 2017-02-23 00:35:29 +03:00
parent dac72ff371
commit 7c418f7ea5
4 changed files with 56 additions and 62 deletions

View file

@ -867,7 +867,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
add_block(_ptr.addr()); add_block(_ptr.addr());
} }
if (op.lk && (target == iaddr || test(pfunc->attr, ppu_attr::no_return))) if (is_call && test(pfunc->attr, ppu_attr::no_return))
{ {
// Nothing // Nothing
} }
@ -946,8 +946,13 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
block.second = _ptr.addr() - block.first; block.second = _ptr.addr() - block.first;
break; break;
} }
else if (op.opcode == ppu_instructions::TRAP()) else if (type == ppu_itype::TW || type == ppu_itype::TWI || type == ppu_itype::TD || type == ppu_itype::TDI)
{ {
if (op.opcode != ppu_instructions::TRAP())
{
add_block(_ptr.addr());
}
block.second = _ptr.addr() - block.first; block.second = _ptr.addr() - block.first;
break; break;
} }

View file

@ -790,14 +790,6 @@ static void ppu_initialize()
f->addAttribute(1, Attribute::NoAlias); f->addAttribute(1, Attribute::NoAlias);
translator->AddFunction(info.addr, f); translator->AddFunction(info.addr, f);
} }
for (const auto& b : info.blocks)
{
if (b.second)
{
translator->AddBlockInfo(b.first);
}
}
} }
legacy::FunctionPassManager pm(module.get()); legacy::FunctionPassManager pm(module.get());

View file

@ -116,11 +116,6 @@ void PPUTranslator::AddFunction(u64 addr, Function* func, FunctionType* type)
} }
} }
void PPUTranslator::AddBlockInfo(u64 addr)
{
m_block_info.emplace(addr);
}
Function* PPUTranslator::TranslateToIR(const ppu_function& info, be_t<u32>* bin, void(*custom)(PPUTranslator*)) Function* PPUTranslator::TranslateToIR(const ppu_function& info, be_t<u32>* bin, void(*custom)(PPUTranslator*))
{ {
m_function = m_func_list[info.addr]; m_function = m_func_list[info.addr];
@ -225,8 +220,19 @@ Function* PPUTranslator::TranslateToIR(const ppu_function& info, be_t<u32>* bin,
m_jtr = BasicBlock::Create(m_context, "__jtr", m_function); m_jtr = BasicBlock::Create(m_context, "__jtr", m_function);
// Create basic blocks
for (auto&& block : info.blocks)
{
if (block.second && block.first >= m_start_addr && block.first < m_end_addr)
{
m_blocks[block.first] = BasicBlock::Create(m_context, fmt::format("loc_%llx", block.first), m_function);
}
}
m_blocks[m_end_addr] = BasicBlock::Create(m_context, "loc_end", m_function);
/* Convert each instruction to LLVM IR */ /* Convert each instruction to LLVM IR */
const auto start = GetBasicBlock(m_start_addr); const auto start = m_blocks.at(m_start_addr);
m_ir->CreateBr(start); m_ir->CreateBr(start);
m_ir->SetInsertPoint(start); m_ir->SetInsertPoint(start);
@ -235,7 +241,7 @@ Function* PPUTranslator::TranslateToIR(const ppu_function& info, be_t<u32>* bin,
// Preserve current address (m_current_addr may be changed by the decoder) // Preserve current address (m_current_addr may be changed by the decoder)
const u64 addr = m_current_addr; const u64 addr = m_current_addr;
if (m_current_addr == m_start_addr || info.blocks.count(m_current_addr)) if (m_blocks.count(m_current_addr))
{ {
// Bloat the beginning of each block: check state // Bloat the beginning of each block: check state
const auto vstate = m_ir->CreateLoad(m_ir->CreateConstGEP2_32(nullptr, m_thread, 0, 1)); const auto vstate = m_ir->CreateLoad(m_ir->CreateConstGEP2_32(nullptr, m_thread, 0, 1));
@ -250,23 +256,29 @@ Function* PPUTranslator::TranslateToIR(const ppu_function& info, be_t<u32>* bin,
} }
// Translate opcode // Translate opcode
const u32 op = *(m_bin = bin + (addr - m_start_addr) / sizeof(u32));
(this->*(s_ppu_decoder.decode(op)))({op});
// Calculate next address if necessary
if (m_current_addr == addr) m_current_addr += sizeof(u32);
// Get next block
const auto next = GetBasicBlock(m_current_addr);
// Finalize current block if necessary (create branch to next address)
if (!m_ir->GetInsertBlock()->getTerminator()) if (!m_ir->GetInsertBlock()->getTerminator())
{ {
m_ir->CreateBr(next); const u32 op = *(m_bin = bin + (addr - m_start_addr) / sizeof(u32));
(this->*(s_ppu_decoder.decode(op)))({op});
} }
// Start next block // Get next address
m_ir->SetInsertPoint(next); if (m_current_addr == addr) m_current_addr += sizeof(u32);
// Get next block if necessary
if (m_blocks.count(m_current_addr))
{
const auto next = m_blocks.at(m_current_addr);
// Finalize current block if necessary (create branch to next address)
if (!m_ir->GetInsertBlock()->getTerminator())
{
m_ir->CreateBr(next);
}
// Start next block
m_ir->SetInsertPoint(next);
}
} }
// Run custom IR generation function // Run custom IR generation function
@ -287,22 +299,28 @@ Function* PPUTranslator::TranslateToIR(const ppu_function& info, be_t<u32>* bin,
} }
else else
{ {
// Get block entries
const std::vector<u64> cases{m_block_info.upper_bound(m_start_addr), m_block_info.lower_bound(m_end_addr)};
const auto _ctr = m_ir->CreateLoad(m_reg_ctr); const auto _ctr = m_ir->CreateLoad(m_reg_ctr);
const auto _default = BasicBlock::Create(m_context, "__jtr.def", m_function); const auto _default = BasicBlock::Create(m_context, "__jtr.def", m_function);
const auto _switch = m_ir->CreateSwitch(_ctr, _default, ::size32(cases)); const auto _switch = m_ir->CreateSwitch(_ctr, _default, ::size32(m_blocks));
for (const u64 addr : cases) for (const auto& pair : m_blocks)
{ {
_switch->addCase(m_ir->getInt64(addr), GetBasicBlock(addr)); _switch->addCase(m_ir->getInt64(pair.first), pair.second);
} }
m_ir->SetInsertPoint(_default); m_ir->SetInsertPoint(_default);
CallFunction(0, true, _ctr); CallFunction(0, true, _ctr);
} }
for (auto&& block : *m_function)
{
if (!block.getTerminator())
{
m_ir->SetInsertPoint(&block);
m_ir->CreateUnreachable();
}
}
return m_function; return m_function;
} }
@ -394,18 +412,6 @@ void PPUTranslator::UndefineVolatileRegisters()
//m_ir->CreateStore(m_ir->getFalse(), m_vscr_sat); // VSCR.SAT //m_ir->CreateStore(m_ir->getFalse(), m_vscr_sat); // VSCR.SAT
} }
BasicBlock* PPUTranslator::GetBasicBlock(u64 address)
{
if (auto& block = m_blocks[address])
{
return block;
}
else
{
return block = BasicBlock::Create(m_context, fmt::format("loc_%llx", address/* - m_start_addr*/), m_function);
}
}
Value* PPUTranslator::Solid(Value* value) Value* PPUTranslator::Solid(Value* value)
{ {
const u32 size = value->getType()->getPrimitiveSizeInBits(); const u32 size = value->getType()->getPrimitiveSizeInBits();
@ -565,7 +571,7 @@ void PPUTranslator::UseCondition(MDNode* hint, Value* cond)
if (cond) if (cond)
{ {
const auto local = BasicBlock::Create(m_context, fmt::format("loc_%llx.cond", m_current_addr/* - m_start_addr*/), m_function); const auto local = BasicBlock::Create(m_context, fmt::format("loc_%llx.cond", m_current_addr/* - m_start_addr*/), m_function);
m_ir->CreateCondBr(cond, local, GetBasicBlock(m_current_addr + 4), hint); m_ir->CreateCondBr(cond, local, m_blocks.at(m_current_addr + 4), hint);
m_ir->SetInsertPoint(local); m_ir->SetInsertPoint(local);
} }
} }
@ -1761,12 +1767,12 @@ void PPUTranslator::BC(ppu_opcode_t op)
} }
else if (cond) else if (cond)
{ {
m_ir->CreateCondBr(cond, GetBasicBlock(target), GetBasicBlock(m_current_addr + 4), CheckBranchProbability(op.bo)); m_ir->CreateCondBr(cond, m_blocks.at(target), m_blocks.at(m_current_addr + 4), CheckBranchProbability(op.bo));
return; return;
} }
else else
{ {
m_ir->CreateBr(GetBasicBlock(target)); m_ir->CreateBr(m_blocks.at(target));
return; return;
} }
} }
@ -1809,7 +1815,7 @@ void PPUTranslator::B(ppu_opcode_t op)
} }
else else
{ {
m_ir->CreateBr(GetBasicBlock(target)); m_ir->CreateBr(m_blocks.at(target));
return; return;
} }
} }
@ -1927,7 +1933,7 @@ void PPUTranslator::BCCTR(ppu_opcode_t op)
for (const u64 target : targets) for (const u64 target : targets)
{ {
_switch->addCase(m_ir->getInt64(target), GetBasicBlock(target)); _switch->addCase(m_ir->getInt64(target), m_blocks.at(target));
} }
m_ir->SetInsertPoint(_default); m_ir->SetInsertPoint(_default);

View file

@ -139,9 +139,6 @@ class PPUTranslator final //: public CPUTranslator
// Basic blocks for current function // Basic blocks for current function
std::unordered_map<u64, llvm::BasicBlock*> m_blocks; std::unordered_map<u64, llvm::BasicBlock*> m_blocks;
// Supplementary block info for all functions
std::set<u64> m_block_info;
// JT resolver block // JT resolver block
llvm::BasicBlock* m_jtr; llvm::BasicBlock* m_jtr;
@ -239,9 +236,6 @@ public:
// Set some registers to undef (after function call) // Set some registers to undef (after function call)
void UndefineVolatileRegisters(); void UndefineVolatileRegisters();
// Get the basic block for the specified address
llvm::BasicBlock* GetBasicBlock(u64 addr);
// Load gpr // Load gpr
llvm::Value* GetGpr(u32 r, u32 num_bits = 64); llvm::Value* GetGpr(u32 r, u32 num_bits = 64);
@ -447,9 +441,6 @@ public:
// Add function // Add function
void AddFunction(u64 addr, llvm::Function* func, llvm::FunctionType* type = nullptr); void AddFunction(u64 addr, llvm::Function* func, llvm::FunctionType* type = nullptr);
// Add block entry hint (not essential)
void AddBlockInfo(u64 addr);
// Parses PPU opcodes and translate them into LLVM IR // Parses PPU opcodes and translate them into LLVM IR
llvm::Function* TranslateToIR(const ppu_function& info, be_t<u32>* bin, void(*custom)(PPUTranslator*) = nullptr); llvm::Function* TranslateToIR(const ppu_function& info, be_t<u32>* bin, void(*custom)(PPUTranslator*) = nullptr);