PPU LLVM: v2, simplification (no allocas)

This commit is contained in:
Nekotekina 2017-06-25 23:34:15 +03:00
parent 45fae363c6
commit cd4f290d3d
4 changed files with 142 additions and 166 deletions

View file

@ -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

View file

@ -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

View file

@ -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));

View file

@ -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();