mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-22 04:25:19 +00:00
PPU LLVM: v2, simplification (no allocas)
This commit is contained in:
parent
45fae363c6
commit
cd4f290d3d
4 changed files with 142 additions and 166 deletions
|
@ -1205,7 +1205,7 @@ extern void ppu_initialize(const ppu_module& info)
|
|||
sha1_finish(&ctx, output);
|
||||
|
||||
// Version, module name and hash: vX-liblv2.sprx-0123456789ABCDEF.obj
|
||||
fmt::append(obj_name, "v1%s-%016X-%s.obj", part.name, reinterpret_cast<be_t<u64>&>(output), jit.cpu());
|
||||
fmt::append(obj_name, "v2%s-%016X-%s.obj", part.name, reinterpret_cast<be_t<u64>&>(output), jit.cpu());
|
||||
}
|
||||
|
||||
if (Emu.IsStopped())
|
||||
|
@ -1352,7 +1352,7 @@ static void ppu_initialize2(jit_compiler& jit, const ppu_module& module_part, co
|
|||
|
||||
Emu.CallAfter([=]()
|
||||
{
|
||||
dlg->Create("Compiling PPU module " + obj_name + "\nPlease wait...");
|
||||
dlg->Create("Compiling PPU module:\n" + obj_name + "\nPlease wait...");
|
||||
});
|
||||
|
||||
// Translate functions
|
||||
|
|
|
@ -38,11 +38,23 @@ public:
|
|||
f64 fpr[32] = {}; // Floating Point Registers
|
||||
v128 vr[32] = {}; // Vector Registers
|
||||
|
||||
alignas(16) bool cr[32] = {}; // Condition Registers (abstract representation)
|
||||
alignas(16) bool cr[32] = {}; // Condition Registers (unpacked)
|
||||
|
||||
alignas(16) struct // Floating-Point Status and Control Register (unpacked)
|
||||
{
|
||||
// TODO
|
||||
bool _start[16]{};
|
||||
bool fl{}; // FPCC.FL
|
||||
bool fg{}; // FPCC.FG
|
||||
bool fe{}; // FPCC.FE
|
||||
bool fu{}; // FPCC.FU
|
||||
bool _end[12]{};
|
||||
}
|
||||
fpscr;
|
||||
|
||||
u64 lr{}; // Link Register
|
||||
u64 ctr{}; // Counter Register
|
||||
u32 vrsave{0xffffffff}; // VR Save Register (almost unused)
|
||||
u32 vrsave{0xffffffff}; // VR Save Register
|
||||
u32 cia{}; // Current Instruction Address
|
||||
|
||||
// Pack CR bits
|
||||
|
@ -111,15 +123,6 @@ public:
|
|||
*/
|
||||
bool nj = true;
|
||||
|
||||
struct // Floating-Point Status and Control Register (abstract representation)
|
||||
{
|
||||
bool fl{}; // FPCC.FL
|
||||
bool fg{}; // FPCC.FG
|
||||
bool fe{}; // FPCC.FE
|
||||
bool fu{}; // FPCC.FU
|
||||
}
|
||||
fpscr;
|
||||
|
||||
u32 raddr{0}; // Reservation addr
|
||||
u64 rtime{0};
|
||||
u64 rdata{0}; // Reservation data
|
||||
|
|
|
@ -85,11 +85,12 @@ PPUTranslator::PPUTranslator(LLVMContext& context, Module* module, u64 base)
|
|||
thread_struct.insert(thread_struct.end(), 32, GetType<f64>()); // fpr[0..31]
|
||||
thread_struct.insert(thread_struct.end(), 32, GetType<u32[4]>()); // vr[0..31]
|
||||
thread_struct.insert(thread_struct.end(), 32, GetType<bool>()); // cr[0..31]
|
||||
thread_struct.insert(thread_struct.end(), 32, GetType<bool>()); // fpscr
|
||||
thread_struct.insert(thread_struct.end(), 2, GetType<u64>()); // lr, ctr
|
||||
thread_struct.insert(thread_struct.end(), 2, GetType<u32>()); // vrsave, cia
|
||||
thread_struct.insert(thread_struct.end(), 3, GetType<bool>()); // so, ov, ca
|
||||
thread_struct.insert(thread_struct.end(), 1, GetType<u8>()); // cnt
|
||||
thread_struct.insert(thread_struct.end(), 6, GetType<bool>()); // sat, nj, FPCC
|
||||
thread_struct.insert(thread_struct.end(), 2, GetType<bool>()); // sat, nj
|
||||
|
||||
m_thread_type = StructType::create(m_context, thread_struct, "context_t");
|
||||
|
||||
|
@ -122,19 +123,24 @@ Function* PPUTranslator::Translate(const ppu_function& info)
|
|||
|
||||
std::fill(std::begin(m_globals), std::end(m_globals), nullptr);
|
||||
std::fill(std::begin(m_locals), std::end(m_locals), nullptr);
|
||||
std::fill(std::begin(m_writes), std::end(m_writes), false);
|
||||
std::fill(std::begin(m_reads), std::end(m_reads), false);
|
||||
|
||||
/* Create builders */
|
||||
IRBuilder<> irb(m_entry = BasicBlock::Create(m_context, "__entry", m_function));
|
||||
m_ir = &irb;
|
||||
|
||||
m_body = BasicBlock::Create(m_context, "__body", m_function);
|
||||
irb.SetInsertPoint(m_body);
|
||||
|
||||
/* Create context variables */
|
||||
m_thread = &*m_function->getArgumentList().begin();
|
||||
m_base_loaded = m_ir->CreateLoad(m_base);
|
||||
m_body = BasicBlock::Create(m_context, "__body", m_function);
|
||||
|
||||
// Check status register in the entry block
|
||||
const auto vstate = m_ir->CreateLoad(m_ir->CreateStructGEP(nullptr, m_thread, 1), true);
|
||||
const auto vcheck = BasicBlock::Create(m_context, "__test", m_function);
|
||||
m_ir->CreateCondBr(m_ir->CreateIsNull(vstate), m_body, vcheck, m_md_likely);
|
||||
|
||||
// Create tail call to the check function
|
||||
m_ir->SetInsertPoint(vcheck);
|
||||
Call(GetType<void>(), "__check", m_thread, m_ir->getInt64(m_start_addr));
|
||||
m_ir->CreateRetVoid();
|
||||
m_ir->SetInsertPoint(m_body);
|
||||
|
||||
// Process blocks
|
||||
const auto block = std::make_pair(info.addr, info.size);
|
||||
|
@ -211,61 +217,54 @@ void PPUTranslator::CallFunction(u64 target, Value* indirect)
|
|||
m_ir->CreateRetVoid();
|
||||
}
|
||||
|
||||
void PPUTranslator::FlushRegisters()
|
||||
Value* PPUTranslator::RegInit(Value*& local)
|
||||
{
|
||||
if (m_entry->getTerminator())
|
||||
const auto index = ::narrow<uint>(&local - m_locals);
|
||||
|
||||
if (!m_globals[index])
|
||||
{
|
||||
return;
|
||||
// Initialize global, will be written in FlushRegisters
|
||||
m_globals[index] = m_ir->CreateStructGEP(nullptr, m_thread, index);
|
||||
}
|
||||
|
||||
auto process = [&](Value*& local, u32 index)
|
||||
return m_globals[index];
|
||||
}
|
||||
|
||||
Value* PPUTranslator::RegLoad(Value*& local)
|
||||
{
|
||||
const uint index = ::narrow<uint>(&local - m_locals);
|
||||
|
||||
if (local)
|
||||
{
|
||||
// Create pointer to the global variable
|
||||
m_ir->SetInsertPoint(m_entry);
|
||||
const auto ptr = m_ir->CreateStructGEP(nullptr, m_thread, index);
|
||||
// Simple load
|
||||
assert(!m_globals[index] || m_globals[index]->getType() == local->getType()->getPointerTo());
|
||||
return local;
|
||||
}
|
||||
|
||||
// Load variable if necessary
|
||||
if (m_reads[&local - m_locals])
|
||||
// Load from the global value
|
||||
local = m_ir->CreateLoad(m_ir->CreateStructGEP(nullptr, m_thread, index));
|
||||
return local;
|
||||
}
|
||||
|
||||
void PPUTranslator::RegStore(llvm::Value* value, llvm::Value*& local)
|
||||
{
|
||||
const auto glb = RegInit(local);
|
||||
assert(glb->getType() == value->getType()->getPointerTo());
|
||||
local = value;
|
||||
}
|
||||
|
||||
void PPUTranslator::FlushRegisters()
|
||||
{
|
||||
for (auto& local : m_locals)
|
||||
{
|
||||
const uint index = ::narrow<uint>(&local - m_locals);
|
||||
|
||||
if (local && m_globals[index])
|
||||
{
|
||||
m_ir->CreateStore(m_ir->CreateLoad(ptr), local);
|
||||
// Store value if necessary
|
||||
m_ir->CreateStore(local, m_globals[index]);
|
||||
}
|
||||
|
||||
m_ir->SetInsertPoint(m_body);
|
||||
|
||||
// Store variable if necessary
|
||||
if (m_writes[&local - m_locals])
|
||||
{
|
||||
m_ir->CreateStore(m_ir->CreateLoad(local), ptr);
|
||||
}
|
||||
|
||||
// Save global
|
||||
m_globals[&local - m_locals] = ptr;
|
||||
};
|
||||
|
||||
|
||||
for (u32 i = 0; i < 32; i++) if (m_gpr[i]) process(m_gpr[i], 3 + i);
|
||||
for (u32 i = 0; i < 32; i++) if (m_fpr[i]) process(m_fpr[i], 35 + i);
|
||||
for (u32 i = 0; i < 32; i++) if (m_vr[i]) process(m_vr[i], 67 + i);
|
||||
for (u32 i = 0; i < 32; i++) if (m_cr[i]) process(m_cr[i], 99 + i);
|
||||
if (m_lr) process(m_lr, 131);
|
||||
if (m_ctr) process(m_ctr, 132);
|
||||
if (m_vrsave) process(m_vrsave, 133);
|
||||
if (m_so) process(m_so, 135);
|
||||
if (m_ov) process(m_ov, 136);
|
||||
if (m_ca) process(m_ca, 137);
|
||||
if (m_cnt) process(m_cnt, 138);
|
||||
if (m_sat) process(m_sat, 139);
|
||||
if (m_nj) process(m_nj, 140);
|
||||
for (u32 i = 16; i < 20; i++) if (m_fc[i]) process(m_fc[i], 141 + i - 16);
|
||||
|
||||
m_ir->SetInsertPoint(m_entry);
|
||||
const auto vstate = m_ir->CreateLoad(m_ir->CreateStructGEP(nullptr, m_thread, 1), true);
|
||||
const auto vcheck = BasicBlock::Create(m_context, "__test", m_function);
|
||||
m_ir->CreateCondBr(m_ir->CreateIsNull(vstate), m_body, vcheck, m_md_likely);
|
||||
m_ir->SetInsertPoint(vcheck);
|
||||
Call(GetType<void>(), "__check", m_thread, m_ir->getInt64(m_start_addr));
|
||||
m_ir->CreateRetVoid();
|
||||
m_ir->SetInsertPoint(m_body);
|
||||
}
|
||||
}
|
||||
|
||||
Value* PPUTranslator::Solid(Value* value)
|
||||
|
@ -482,15 +481,15 @@ void PPUTranslator::CompilationError(const std::string& error)
|
|||
|
||||
void PPUTranslator::MFVSCR(ppu_opcode_t op)
|
||||
{
|
||||
const auto vscr = m_ir->CreateOr(ZExt(RegLoad<bool>(m_sat), GetType<u32>()), m_ir->CreateShl(ZExt(RegLoad<bool>(m_nj), GetType<u32>()), 16));
|
||||
const auto vscr = m_ir->CreateOr(ZExt(RegLoad(m_sat), GetType<u32>()), m_ir->CreateShl(ZExt(RegLoad(m_nj), GetType<u32>()), 16));
|
||||
SetVr(op.vd, m_ir->CreateInsertElement(ConstantVector::getSplat(4, m_ir->getInt32(0)), vscr, m_ir->getInt32(m_is_be ? 3 : 0)));
|
||||
}
|
||||
|
||||
void PPUTranslator::MTVSCR(ppu_opcode_t op)
|
||||
{
|
||||
const auto vscr = m_ir->CreateExtractElement(GetVr(op.vb, VrType::vi32), m_ir->getInt32(m_is_be ? 3 : 0));
|
||||
RegStore<bool>(Trunc(m_ir->CreateLShr(vscr, 16), GetType<bool>()), m_nj);
|
||||
RegStore<bool>(Trunc(vscr, GetType<bool>()), m_sat);
|
||||
RegStore(Trunc(m_ir->CreateLShr(vscr, 16), GetType<bool>()), m_nj);
|
||||
RegStore(Trunc(vscr, GetType<bool>()), m_sat);
|
||||
}
|
||||
|
||||
void PPUTranslator::VADDCUW(ppu_opcode_t op)
|
||||
|
@ -1612,7 +1611,7 @@ void PPUTranslator::BC(ppu_opcode_t op)
|
|||
{
|
||||
if (op.lk)
|
||||
{
|
||||
RegInit<u64>(m_lr);
|
||||
RegInit(m_lr);
|
||||
}
|
||||
|
||||
const u64 target = (op.aa ? 0 : m_current_addr) + op.bt14;
|
||||
|
@ -1635,8 +1634,8 @@ void PPUTranslator::SC(ppu_opcode_t op)
|
|||
}
|
||||
|
||||
const auto num = GetGpr(11);
|
||||
RegStore(m_ir->getInt32(m_current_addr), m_cia);
|
||||
FlushRegisters();
|
||||
m_ir->CreateStore(m_ir->getInt32(m_current_addr), m_ir->CreateStructGEP(nullptr, m_thread, 134));
|
||||
Call(GetType<void>(), op.lev ? "__lv1call" : "__syscall", m_thread, num);
|
||||
m_ir->CreateRetVoid();
|
||||
}
|
||||
|
@ -1647,7 +1646,7 @@ void PPUTranslator::B(ppu_opcode_t op)
|
|||
|
||||
if (op.lk)
|
||||
{
|
||||
RegStore<u64>(m_ir->getInt64(m_current_addr + 4), m_lr);
|
||||
RegStore(m_ir->getInt64(m_current_addr + 4), m_lr);
|
||||
}
|
||||
|
||||
FlushRegisters();
|
||||
|
@ -1665,7 +1664,9 @@ void PPUTranslator::MCRF(ppu_opcode_t op)
|
|||
|
||||
void PPUTranslator::BCLR(ppu_opcode_t op)
|
||||
{
|
||||
const auto target = RegLoad<u64>(m_lr);
|
||||
RegInit(m_lr);
|
||||
|
||||
const auto target = RegLoad(m_lr);
|
||||
|
||||
UseCondition(CheckBranchProbability(op.bo), CheckBranchCondition(op.bo, op.bi));
|
||||
|
||||
|
@ -1730,10 +1731,10 @@ void PPUTranslator::BCCTR(ppu_opcode_t op)
|
|||
{
|
||||
if (op.lk)
|
||||
{
|
||||
RegInit<u64>(m_lr);
|
||||
RegInit(m_lr);
|
||||
}
|
||||
|
||||
const auto target = RegLoad<u64>(m_ctr);
|
||||
const auto target = RegLoad(m_ctr);
|
||||
|
||||
UseCondition(CheckBranchProbability(op.bo | 0x4), CheckBranchCondition(op.bo | 0x4, op.bi));
|
||||
|
||||
|
@ -2589,19 +2590,19 @@ void PPUTranslator::MFSPR(ppu_opcode_t op)
|
|||
switch (const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5))
|
||||
{
|
||||
case 0x001: // MFXER
|
||||
result = ZExt(RegLoad<u8>(m_cnt), GetType<u64>());
|
||||
result = m_ir->CreateOr(result, m_ir->CreateShl(ZExt(RegLoad<bool>(m_so), GetType<u64>()), 29));
|
||||
result = m_ir->CreateOr(result, m_ir->CreateShl(ZExt(RegLoad<bool>(m_ov), GetType<u64>()), 30));
|
||||
result = m_ir->CreateOr(result, m_ir->CreateShl(ZExt(RegLoad<bool>(m_ca), GetType<u64>()), 31));
|
||||
result = ZExt(RegLoad(m_cnt), GetType<u64>());
|
||||
result = m_ir->CreateOr(result, m_ir->CreateShl(ZExt(RegLoad(m_so), GetType<u64>()), 29));
|
||||
result = m_ir->CreateOr(result, m_ir->CreateShl(ZExt(RegLoad(m_ov), GetType<u64>()), 30));
|
||||
result = m_ir->CreateOr(result, m_ir->CreateShl(ZExt(RegLoad(m_ca), GetType<u64>()), 31));
|
||||
break;
|
||||
case 0x008: // MFLR
|
||||
result = RegLoad<u64>(m_lr);
|
||||
result = RegLoad(m_lr);
|
||||
break;
|
||||
case 0x009: // MFCTR
|
||||
result = RegLoad<u64>(m_ctr);
|
||||
result = RegLoad(m_ctr);
|
||||
break;
|
||||
case 0x100:
|
||||
result = ZExt(RegLoad<u32>(m_vrsave));
|
||||
result = ZExt(RegLoad(m_vrsave));
|
||||
break;
|
||||
case 0x10C: // MFTB
|
||||
result = Call(GetType<u64>(), m_pure_attr, "__get_tb");
|
||||
|
@ -2733,19 +2734,19 @@ void PPUTranslator::MTSPR(ppu_opcode_t op)
|
|||
switch (const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5))
|
||||
{
|
||||
case 0x001: // MTXER
|
||||
RegStore<bool>(Trunc(m_ir->CreateLShr(value, 31), GetType<bool>()), m_ca);
|
||||
RegStore<bool>(Trunc(m_ir->CreateLShr(value, 30), GetType<bool>()), m_ov);
|
||||
RegStore<bool>(Trunc(m_ir->CreateLShr(value, 29), GetType<bool>()), m_so);
|
||||
RegStore<u8>(Trunc(value, GetType<u8>()), m_cnt);
|
||||
RegStore(Trunc(m_ir->CreateLShr(value, 31), GetType<bool>()), m_ca);
|
||||
RegStore(Trunc(m_ir->CreateLShr(value, 30), GetType<bool>()), m_ov);
|
||||
RegStore(Trunc(m_ir->CreateLShr(value, 29), GetType<bool>()), m_so);
|
||||
RegStore(Trunc(value, GetType<u8>()), m_cnt);
|
||||
break;
|
||||
case 0x008: // MTLR
|
||||
RegStore<u64>(value, m_lr);
|
||||
RegStore(value, m_lr);
|
||||
break;
|
||||
case 0x009: // MTCTR
|
||||
RegStore<u64>(value, m_ctr);
|
||||
RegStore(value, m_ctr);
|
||||
break;
|
||||
case 0x100:
|
||||
RegStore<u32>(Trunc(value), m_vrsave);
|
||||
RegStore(Trunc(value), m_vrsave);
|
||||
break;
|
||||
default:
|
||||
Call(GetType<void>(), fmt::format("__mtspr_%u", n), value);
|
||||
|
@ -2799,7 +2800,7 @@ void PPUTranslator::LDBRX(ppu_opcode_t op)
|
|||
|
||||
void PPUTranslator::LSWX(ppu_opcode_t op)
|
||||
{
|
||||
Call(GetType<void>(), "__lswx", m_ir->getInt32(op.rd), RegLoad<u8>(m_cnt), op.ra ? m_ir->CreateAdd(GetGpr(op.ra), GetGpr(op.rb)) : GetGpr(op.rb));
|
||||
Call(GetType<void>(), "__lswx", m_ir->getInt32(op.rd), RegLoad(m_cnt), op.ra ? m_ir->CreateAdd(GetGpr(op.ra), GetGpr(op.rb)) : GetGpr(op.rb));
|
||||
}
|
||||
|
||||
void PPUTranslator::LWBRX(ppu_opcode_t op)
|
||||
|
@ -2912,7 +2913,7 @@ void PPUTranslator::STDBRX(ppu_opcode_t op)
|
|||
|
||||
void PPUTranslator::STSWX(ppu_opcode_t op)
|
||||
{
|
||||
Call(GetType<void>(), "__stswx", m_ir->getInt32(op.rs), RegLoad<u8>(m_cnt), op.ra ? m_ir->CreateAdd(GetGpr(op.ra), GetGpr(op.rb)) : GetGpr(op.rb));
|
||||
Call(GetType<void>(), "__stswx", m_ir->getInt32(op.rs), RegLoad(m_cnt), op.ra ? m_ir->CreateAdd(GetGpr(op.ra), GetGpr(op.rb)) : GetGpr(op.rb));
|
||||
}
|
||||
|
||||
void PPUTranslator::STWBRX(ppu_opcode_t op)
|
||||
|
@ -3503,7 +3504,7 @@ void PPUTranslator::MFFS(ppu_opcode_t op)
|
|||
|
||||
for (u32 i = 16; i < 20; i++)
|
||||
{
|
||||
result = m_ir->CreateOr(result, m_ir->CreateShl(ZExt(RegLoad<bool>(m_fc[i]), GetType<u64>()), i ^ 31));
|
||||
result = m_ir->CreateOr(result, m_ir->CreateShl(ZExt(RegLoad(m_fc[i]), GetType<u64>()), i ^ 31));
|
||||
}
|
||||
|
||||
SetFpr(op.frd, result);
|
||||
|
@ -3845,17 +3846,17 @@ void PPUTranslator::UNK(ppu_opcode_t op)
|
|||
|
||||
Value* PPUTranslator::GetGpr(u32 r, u32 num_bits)
|
||||
{
|
||||
return m_ir->CreateTrunc(RegLoad<u64>(m_gpr[r]), m_ir->getIntNTy(num_bits));
|
||||
return m_ir->CreateTrunc(RegLoad(m_gpr[r]), m_ir->getIntNTy(num_bits));
|
||||
}
|
||||
|
||||
void PPUTranslator::SetGpr(u32 r, Value* value)
|
||||
{
|
||||
RegStore<u64>(m_ir->CreateZExt(value, GetType<u64>()), m_gpr[r]);
|
||||
RegStore(m_ir->CreateZExt(value, GetType<u64>()), m_gpr[r]);
|
||||
}
|
||||
|
||||
Value* PPUTranslator::GetFpr(u32 r, u32 bits, bool as_int)
|
||||
{
|
||||
const auto value = RegLoad<f64>(m_fpr[r]);
|
||||
const auto value = RegLoad(m_fpr[r]);
|
||||
|
||||
if (!as_int && bits == 64)
|
||||
{
|
||||
|
@ -3878,16 +3879,12 @@ void PPUTranslator::SetFpr(u32 r, Value* val)
|
|||
val->getType() == GetType<s64>() ? m_ir->CreateBitCast(val, GetType<f64>()) :
|
||||
val->getType() == GetType<f32>() ? m_ir->CreateFPExt(val, GetType<f64>()) : val;
|
||||
|
||||
RegStore<f64>(f64_val, m_fpr[r]);
|
||||
RegStore(f64_val, m_fpr[r]);
|
||||
}
|
||||
|
||||
Value* PPUTranslator::GetVr(u32 vr, VrType type)
|
||||
{
|
||||
RegInit<u32[4]>(m_vr[vr]);
|
||||
|
||||
m_reads[&m_vr[vr] - m_locals] = true;
|
||||
|
||||
const auto value = m_ir->CreateAlignedLoad(m_vr[vr], 16);
|
||||
const auto value = RegLoad(m_vr[vr]);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
|
@ -3903,10 +3900,6 @@ Value* PPUTranslator::GetVr(u32 vr, VrType type)
|
|||
|
||||
void PPUTranslator::SetVr(u32 vr, Value* value)
|
||||
{
|
||||
RegInit<u32[4]>(m_vr[vr]);
|
||||
|
||||
m_writes[&m_vr[vr] - m_locals] = true;
|
||||
|
||||
const auto type = value->getType();
|
||||
const auto size = type->getPrimitiveSizeInBits();
|
||||
|
||||
|
@ -3924,17 +3917,17 @@ void PPUTranslator::SetVr(u32 vr, Value* value)
|
|||
}
|
||||
}
|
||||
|
||||
m_ir->CreateAlignedStore(m_ir->CreateBitCast(value, GetType<u32[4]>()), m_vr[vr], 16);
|
||||
RegStore(m_ir->CreateBitCast(value, GetType<u32[4]>()), m_vr[vr]);
|
||||
}
|
||||
|
||||
Value* PPUTranslator::GetCrb(u32 crb)
|
||||
{
|
||||
return RegLoad<bool>(m_cr[crb]);
|
||||
return RegLoad(m_cr[crb]);
|
||||
}
|
||||
|
||||
void PPUTranslator::SetCrb(u32 crb, Value* value)
|
||||
{
|
||||
RegStore<bool>(value, m_cr[crb]);
|
||||
RegStore(value, m_cr[crb]);
|
||||
}
|
||||
|
||||
void PPUTranslator::SetCrField(u32 group, Value* lt, Value* gt, Value* eq, Value* so)
|
||||
|
@ -3942,7 +3935,7 @@ void PPUTranslator::SetCrField(u32 group, Value* lt, Value* gt, Value* eq, Value
|
|||
SetCrb(group * 4 + 0, lt ? lt : GetUndef<bool>());
|
||||
SetCrb(group * 4 + 1, gt ? gt : GetUndef<bool>());
|
||||
SetCrb(group * 4 + 2, eq ? eq : GetUndef<bool>());
|
||||
SetCrb(group * 4 + 3, so ? so : RegLoad<bool>(m_so));
|
||||
SetCrb(group * 4 + 3, so ? so : RegLoad(m_so));
|
||||
}
|
||||
|
||||
void PPUTranslator::SetCrFieldSignedCmp(u32 n, Value* a, Value* b)
|
||||
|
@ -4039,7 +4032,7 @@ Value* PPUTranslator::GetFPSCRBit(u32 n)
|
|||
}
|
||||
|
||||
// Get bit
|
||||
const auto value = RegLoad<bool>(m_fc[n]);
|
||||
const auto value = RegLoad(m_fc[n]);
|
||||
|
||||
//if (n == 0 || (n >= 3 && n <= 12) || (n >= 21 && n <= 23))
|
||||
//{
|
||||
|
@ -4072,28 +4065,28 @@ void PPUTranslator::SetFPSCRBit(u32 n, Value* value, bool update_fx)
|
|||
//if (n >= 30) CompilationError("SetFPSCRBit: RN bit");
|
||||
|
||||
// Store the bit
|
||||
RegStore<bool>(value, m_fc[n]);
|
||||
RegStore(value, m_fc[n]);
|
||||
}
|
||||
|
||||
Value* PPUTranslator::GetCarry()
|
||||
{
|
||||
return RegLoad<bool>(m_ca);
|
||||
return RegLoad(m_ca);
|
||||
}
|
||||
|
||||
void PPUTranslator::SetCarry(Value* bit)
|
||||
{
|
||||
RegStore<bool>(bit, m_ca);
|
||||
RegStore(bit, m_ca);
|
||||
}
|
||||
|
||||
void PPUTranslator::SetOverflow(Value* bit)
|
||||
{
|
||||
RegStore<bool>(bit, m_ov);
|
||||
RegStore<bool>(m_ir->CreateOr(RegLoad<bool>(m_so), bit), m_so);
|
||||
RegStore(bit, m_ov);
|
||||
RegStore(m_ir->CreateOr(RegLoad(m_so), bit), m_so);
|
||||
}
|
||||
|
||||
void PPUTranslator::SetSat(Value* bit)
|
||||
{
|
||||
RegStore<bool>(m_ir->CreateOr(RegLoad<bool>(m_sat), bit), m_sat);
|
||||
RegStore(m_ir->CreateOr(RegLoad(m_sat), bit), m_sat);
|
||||
}
|
||||
|
||||
Value* PPUTranslator::CheckTrapCondition(u32 to, Value* left, Value* right)
|
||||
|
@ -4121,10 +4114,10 @@ Value* PPUTranslator::CheckBranchCondition(u32 bo, u32 bi)
|
|||
const bool bo3 = (bo & 0x02) != 0;
|
||||
|
||||
// Decrement counter if necessary
|
||||
const auto ctr = bo2 ? nullptr : m_ir->CreateSub(RegLoad<u64>(m_ctr), m_ir->getInt64(1));
|
||||
const auto ctr = bo2 ? nullptr : m_ir->CreateSub(RegLoad(m_ctr), m_ir->getInt64(1));
|
||||
|
||||
// Store counter if necessary
|
||||
if (ctr) RegStore<u64>(ctr, m_ctr);
|
||||
if (ctr) RegStore(ctr, m_ctr);
|
||||
|
||||
// Generate counter condition
|
||||
const auto use_ctr = bo2 ? nullptr : m_ir->CreateICmp(bo3 ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE, ctr, m_ir->getInt64(0));
|
||||
|
|
|
@ -150,59 +150,30 @@ class PPUTranslator final //: public CPUTranslator
|
|||
// Thread context struct
|
||||
llvm::StructType* m_thread_type;
|
||||
|
||||
llvm::Value* m_globals[169];
|
||||
llvm::Value* m_locals[169];
|
||||
llvm::Value** const m_gpr = m_locals + 0;
|
||||
llvm::Value** const m_fpr = m_locals + 32;
|
||||
llvm::Value** const m_vr = m_locals + 64;
|
||||
llvm::Value** const m_cr = m_locals + 96;
|
||||
llvm::Value** const m_fc = m_locals + 128;
|
||||
|
||||
std::array<bool, 169> m_writes;
|
||||
std::array<bool, 169> m_reads;
|
||||
llvm::Value* m_globals[173];
|
||||
llvm::Value* m_locals[173];
|
||||
llvm::Value** const m_gpr = m_locals + 3;
|
||||
llvm::Value** const m_fpr = m_locals + 35;
|
||||
llvm::Value** const m_vr = m_locals + 67;
|
||||
llvm::Value** const m_cr = m_locals + 99;
|
||||
llvm::Value** const m_fc = m_locals + 131; // FPSCR bits (used partially)
|
||||
|
||||
#define DEF_VALUE(loc, glb, pos)\
|
||||
llvm::Value*& loc = m_locals[pos];\
|
||||
llvm::Value*& glb = m_globals[pos];
|
||||
|
||||
DEF_VALUE(m_lr, m_g_lr, 160);
|
||||
DEF_VALUE(m_ctr, m_g_ctr, 161); // CTR register (counter)
|
||||
DEF_VALUE(m_vrsave, m_g_vrsave, 162);
|
||||
DEF_VALUE(m_so, m_g_so, 163); // XER.SO bit, summary overflow
|
||||
DEF_VALUE(m_ov, m_g_ov, 164); // XER.OV bit, overflow flag
|
||||
DEF_VALUE(m_ca, m_g_ca, 165); // XER.CA bit, carry flag
|
||||
DEF_VALUE(m_cnt, m_g_cnt, 166);
|
||||
DEF_VALUE(m_nj, m_g_nj, 167); // VSCR.NJ bit, non-Java mode
|
||||
DEF_VALUE(m_sat, m_g_sat, 168); // VSCR.SAT bit, sticky saturation flag
|
||||
DEF_VALUE(m_lr, m_g_lr, 163); // LR, Link Register
|
||||
DEF_VALUE(m_ctr, m_g_ctr, 164); // CTR, Counter Register
|
||||
DEF_VALUE(m_vrsave, m_g_vrsave, 165);
|
||||
DEF_VALUE(m_cia, m_g_cia, 166);
|
||||
DEF_VALUE(m_so, m_g_so, 167); // XER.SO bit, summary overflow
|
||||
DEF_VALUE(m_ov, m_g_ov, 168); // XER.OV bit, overflow flag
|
||||
DEF_VALUE(m_ca, m_g_ca, 169); // XER.CA bit, carry flag
|
||||
DEF_VALUE(m_cnt, m_g_cnt, 170); // XER.CNT
|
||||
DEF_VALUE(m_sat, m_g_sat, 171); // VSCR.SAT bit, sticky saturation flag
|
||||
DEF_VALUE(m_nj, m_g_nj, 172); // VSCR.NJ bit, non-Java mode
|
||||
|
||||
#undef DEF_VALUE
|
||||
|
||||
template <typename T>
|
||||
void RegInit(llvm::Value*& local)
|
||||
{
|
||||
if (!local)
|
||||
{
|
||||
local = new llvm::AllocaInst(GetType<T>(), nullptr, sizeof(T));
|
||||
m_entry->getInstList().push_back(llvm::cast<llvm::Instruction>(local));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
llvm::Value* RegLoad(llvm::Value*& local)
|
||||
{
|
||||
RegInit<T>(local);
|
||||
m_reads.at(&local - m_locals) = true;
|
||||
return m_ir->CreateLoad(local);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void RegStore(llvm::Value* value, llvm::Value*& local)
|
||||
{
|
||||
RegInit<T>(local);
|
||||
m_writes.at(&local - m_locals) = true;
|
||||
m_ir->CreateStore(value, local);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// Change integer size for integer or integer vector type (by 2^degree)
|
||||
|
@ -220,6 +191,15 @@ public:
|
|||
// Emit function call
|
||||
void CallFunction(u64 target, llvm::Value* indirect = nullptr);
|
||||
|
||||
// Initialize global for writing
|
||||
llvm::Value* RegInit(llvm::Value*& local);
|
||||
|
||||
// Load last register value
|
||||
llvm::Value* RegLoad(llvm::Value*& local);
|
||||
|
||||
// Store register value locally
|
||||
void RegStore(llvm::Value* value, llvm::Value*& local);
|
||||
|
||||
// Write global registers
|
||||
void FlushRegisters();
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue