1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-23 03:02:53 +01:00

PPU LLVM: relocation support

This commit is contained in:
Nekotekina 2017-07-01 02:08:51 +03:00
parent 9fccb47e7c
commit f0d184f38b
7 changed files with 666 additions and 237 deletions

View File

@ -10,7 +10,6 @@
namespace vm { using namespace ps3; }
const ppu_decoder<ppu_itype> s_ppu_itype;
const ppu_decoder<ppu_iname> s_ppu_iname;
template<>
void fmt_class_string<ppu_attr>::format(std::string& out, u64 arg)
@ -36,10 +35,10 @@ void fmt_class_string<bs_t<ppu_attr>>::format(std::string& out, u64 arg)
format_bitset(out, arg, "[", ",", "]", &fmt_class_string<ppu_attr>::format);
}
void ppu_validate(const std::string& fname, const std::vector<ppu_function>& funcs, u32 reloc)
void ppu_module::validate(u32 reloc)
{
// Load custom PRX configuration if available
if (fs::file yml{fname + ".yml"})
if (fs::file yml{path + ".yml"})
{
const auto cfg = YAML::Load(yml.to_string());
@ -57,14 +56,14 @@ void ppu_validate(const std::string& fname, const std::vector<ppu_function>& fun
while (addr > found && index + 1 < funcs.size())
{
LOG_WARNING(LOADER, "%s.yml : unexpected function at 0x%x (0x%x, 0x%x)", fname, found, addr, size);
LOG_WARNING(LOADER, "%s.yml : unexpected function at 0x%x (0x%x, 0x%x)", path, found, addr, size);
index++;
found = funcs[index].addr - reloc;
}
if (addr < found)
{
LOG_ERROR(LOADER, "%s.yml : function not found (0x%x, 0x%x)", fname, addr, size);
LOG_ERROR(LOADER, "%s.yml : function not found (0x%x, 0x%x)", path, addr, size);
continue;
}
@ -72,7 +71,7 @@ void ppu_validate(const std::string& fname, const std::vector<ppu_function>& fun
{
if (size + 4 != funcs[index].size || vm::read32(addr + size) != ppu_instructions::NOP())
{
LOG_ERROR(LOADER, "%s.yml : function size mismatch at 0x%x(size=0x%x) (0x%x, 0x%x)", fname, found, funcs[index].size, addr, size);
LOG_ERROR(LOADER, "%s.yml : function size mismatch at 0x%x(size=0x%x) (0x%x, 0x%x)", path, found, funcs[index].size, addr, size);
}
}
@ -80,7 +79,7 @@ void ppu_validate(const std::string& fname, const std::vector<ppu_function>& fun
}
else
{
LOG_ERROR(LOADER, "%s.yml : function not found at the end (0x%x, 0x%x)", fname, addr, size);
LOG_ERROR(LOADER, "%s.yml : function not found at the end (0x%x, 0x%x)", path, addr, size);
break;
}
}
@ -94,13 +93,13 @@ void ppu_validate(const std::string& fname, const std::vector<ppu_function>& fun
{
if (funcs[index].size)
{
LOG_ERROR(LOADER, "%s.yml : function not covered at 0x%x (size=0x%x)", fname, funcs[index].addr, funcs[index].size);
LOG_ERROR(LOADER, "%s.yml : function not covered at 0x%x (size=0x%x)", path, funcs[index].addr, funcs[index].size);
}
index++;
}
LOG_SUCCESS(LOADER, "%s.yml : validation completed", fname);
LOG_SUCCESS(LOADER, "%s.yml : validation completed", path);
}
}
@ -522,17 +521,17 @@ namespace ppu_patterns
};
}
std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& segs, const std::vector<std::pair<u32, u32>>& secs, u32 lib_toc, u32 entry)
void ppu_module::analyse(u32 lib_toc, u32 entry)
{
// Assume first segment is executable
const u32 start = segs[0].first;
const u32 end = segs[0].first + segs[0].second;
const u32 start = segs[0].addr;
const u32 end = segs[0].addr + segs[0].size;
// Known TOCs (usually only 1)
std::unordered_set<u32> TOCs;
// Known functions
std::map<u32, ppu_function> funcs;
std::map<u32, ppu_function> fmap;
// Function analysis workload
std::vector<std::reference_wrapper<ppu_function>> func_queue;
@ -543,7 +542,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
// Register new function
auto add_func = [&](u32 addr, u32 toc, u32 caller) -> ppu_function&
{
ppu_function& func = funcs[addr];
ppu_function& func = fmap[addr];
if (caller)
{
@ -586,7 +585,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
// Grope for OPD section (TODO: optimization, better constraints)
for (const auto& seg : segs)
{
for (vm::cptr<u32> ptr = vm::cast(seg.first); ptr.addr() < seg.first + seg.second; ptr++)
for (vm::cptr<u32> ptr = vm::cast(seg.addr); ptr.addr() < seg.addr + seg.size; ptr++)
{
if (ptr[0] >= start && ptr[0] < end && ptr[0] % 4 == 0 && ptr[1] == toc)
{
@ -602,7 +601,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
// Get next reliable function address
auto get_limit = [&](u32 addr) -> u32
{
for (auto it = funcs.lower_bound(addr), end = funcs.end(); it != end; it++)
for (auto it = fmap.lower_bound(addr), end = fmap.end(); it != end; it++)
{
if (test(it->second.attr, ppu_attr::known_addr))
{
@ -616,7 +615,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
// Find references indiscriminately
for (const auto& seg : segs)
{
for (vm::cptr<u32> ptr = vm::cast(seg.first); ptr.addr() < seg.first + seg.second; ptr++)
for (vm::cptr<u32> ptr = vm::cast(seg.addr); ptr.addr() < seg.addr + seg.size; ptr++)
{
const u32 value = *ptr;
@ -627,7 +626,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
for (const auto& _seg : segs)
{
if (value >= _seg.first && value < _seg.first + _seg.second)
if (value >= _seg.addr && value < _seg.addr + _seg.size)
{
addr_heap.emplace(value);
break;
@ -639,10 +638,10 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
// Find OPD section
for (const auto& sec : secs)
{
vm::cptr<void> sec_end = vm::cast(sec.first + sec.second);
vm::cptr<void> sec_end = vm::cast(sec.addr + sec.size);
// Probe
for (vm::cptr<u32> ptr = vm::cast(sec.first); ptr < sec_end; ptr += 2)
for (vm::cptr<u32> ptr = vm::cast(sec.addr); ptr < sec_end; ptr += 2)
{
if (ptr + 6 <= sec_end && !ptr[0] && !ptr[2] && ptr[1] == ptr[4] && ptr[3] == ptr[5])
{
@ -677,10 +676,10 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
}
}
if (sec_end) LOG_NOTICE(PPU, "Reading OPD section at 0x%x...", sec.first);
if (sec_end) LOG_NOTICE(PPU, "Reading OPD section at 0x%x...", sec.addr);
// Mine
for (vm::cptr<u32> ptr = vm::cast(sec.first); ptr < sec_end; ptr += 2)
for (vm::cptr<u32> ptr = vm::cast(sec.addr); ptr < sec_end; ptr += 2)
{
// Special case: see "Probe"
if (!ptr[0]) ptr += 4;
@ -709,7 +708,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
}
// Clean TOCs
for (auto&& pair : funcs)
for (auto&& pair : fmap)
{
if (pair.second.toc == -1)
{
@ -720,12 +719,12 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
// Find .eh_frame section
for (const auto& sec : secs)
{
vm::cptr<void> sec_end = vm::cast(sec.first + sec.second);
vm::cptr<void> sec_end = vm::cast(sec.addr + sec.size);
// Probe
for (vm::cptr<u32> ptr = vm::cast(sec.first); ptr < sec_end;)
for (vm::cptr<u32> ptr = vm::cast(sec.addr); ptr < sec_end;)
{
if (ptr % 4 || ptr.addr() < sec.first || ptr >= sec_end)
if (ptr % 4 || ptr.addr() < sec.addr || ptr >= sec_end)
{
sec_end.set(0);
break;
@ -749,7 +748,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
{
const u32 cie_off = ptr.addr() - ptr[1] + 4;
if (cie_off % 4 || cie_off < sec.first || cie_off >= sec_end.addr())
if (cie_off % 4 || cie_off < sec.addr || cie_off >= sec_end.addr())
{
sec_end.set(0);
break;
@ -759,10 +758,10 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
ptr = vm::cast(ptr.addr() + size);
}
if (sec_end && sec.second > 4) LOG_NOTICE(PPU, "Reading .eh_frame section at 0x%x...", sec.first);
if (sec_end && sec.size > 4) LOG_NOTICE(PPU, "Reading .eh_frame section at 0x%x...", sec.addr);
// Mine
for (vm::cptr<u32> ptr = vm::cast(sec.first); ptr < sec_end; ptr = vm::cast(ptr.addr() + ptr[0] + 4))
for (vm::cptr<u32> ptr = vm::cast(sec.addr); ptr < sec_end; ptr = vm::cast(ptr.addr() + ptr[0] + 4))
{
if (ptr[0] == 0)
{
@ -837,7 +836,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
{
for (u32 addr : func.callers)
{
ppu_function& caller = funcs[addr];
ppu_function& caller = fmap[addr];
if (!caller.toc)
{
@ -847,7 +846,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
for (u32 addr : func.calls)
{
ppu_function& callee = funcs[addr];
ppu_function& callee = fmap[addr];
if (!callee.toc)
{
@ -1077,10 +1076,10 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
if (test(func.attr, ppu_attr::no_size))
{
// Get next function
const auto _next = funcs.lower_bound(func.blocks.crbegin()->first + 1);
const auto _next = fmap.lower_bound(func.blocks.crbegin()->first + 1);
// Get limit
const u32 func_end2 = _next == funcs.end() ? func_end : std::min<u32>(_next->first, func_end);
const u32 func_end2 = _next == fmap.end() ? func_end : std::min<u32>(_next->first, func_end);
// Set more block entries
std::for_each(addr_heap.lower_bound(func.addr), addr_heap.lower_bound(func_end2), add_block);
@ -1322,14 +1321,14 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
}
// Function shrinkage, disabled (TODO: it's potentially dangerous but improvable)
for (auto& _pair : funcs)
for (auto& _pair : fmap)
{
auto& func = _pair.second;
// Get next function addr
const auto _next = funcs.lower_bound(_pair.first + 1);
const auto _next = fmap.lower_bound(_pair.first + 1);
const u32 next = _next == funcs.end() ? end : _next->first;
const u32 next = _next == fmap.end() ? end : _next->first;
// Just ensure that functions don't overlap
if (func.addr + func.size > next)
@ -1415,7 +1414,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
{
lib_toc = *TOCs.begin();
for (auto&& pair : funcs)
for (auto&& pair : fmap)
{
if (pair.second.toc == 0)
{
@ -1425,16 +1424,12 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
}
// Convert map to vector (destructive)
std::vector<ppu_function> result;
for (auto&& pair : funcs)
for (auto&& pair : fmap)
{
auto& func = pair.second;
LOG_TRACE(PPU, "Function %s (size=0x%x, toc=0x%x, attr %#x)", func.name, func.size, func.toc, func.attr);
result.emplace_back(std::move(func));
funcs.emplace_back(std::move(func));
}
LOG_NOTICE(PPU, "Function analysis: %zu functions (%zu enqueued)", result.size(), func_queue.size());
return result;
LOG_NOTICE(PPU, "Function analysis: %zu functions (%zu enqueued)", funcs.size(), func_queue.size());
}

View File

@ -38,11 +38,9 @@ struct ppu_function
// PPU Relocation Information
struct ppu_reloc
{
u32 addr;
u32 type;
u32 off;
u32 ptr;
u8 index_value;
u8 index_addr;
u64 data;
};
// PPU Segment Information
@ -58,10 +56,14 @@ struct ppu_segment
struct ppu_module
{
std::string name;
std::vector<ppu_reloc> rels;
std::string path;
std::vector<ppu_reloc> relocs;
std::vector<ppu_segment> segs;
std::vector<ppu_segment> secs;
std::vector<ppu_function> funcs;
std::vector<ppu_segment> sections;
void analyse(u32 lib_toc, u32 entry);
void validate(u32 reloc);
};
// Aux
@ -131,10 +133,6 @@ struct ppu_pattern_matrix
}
};
extern void ppu_validate(const std::string& fname, const std::vector<ppu_function>& funcs, u32 reloc);
extern std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& segs, const std::vector<std::pair<u32, u32>>& secs, u32 lib_toc, u32 entry);
// PPU Instruction Type
struct ppu_itype
{

View File

@ -112,7 +112,7 @@ struct ppu_linkage_info
bool hle = false;
u32 export_addr = 0;
std::set<u32> imports;
std::set<u32> weak_imports;
std::set<u32> frefss;
};
// FNID -> (export; [imports...])
@ -342,9 +342,8 @@ static void ppu_initialize_modules(const std::shared_ptr<ppu_linkage_info>& link
}
}
// Link variables/weak imports, looks to be literally the same as vrefs
// Don't use bool flag in VREFs, originally it didn't have it
static void ppu_patch_refs(u32 fref, u32 faddr)
// Resolve relocations for variable/function linkage.
static void ppu_patch_refs(std::vector<ppu_reloc>* out_relocs, u32 fref, u32 faddr)
{
struct ref_t
{
@ -357,42 +356,52 @@ static void ppu_patch_refs(u32 fref, u32 faddr)
{
if (ref->addend) LOG_WARNING(LOADER, "**** REF(%u): Addend value(0x%x, 0x%x)", ref->type, ref->addr, ref->addend);
const auto ref_import = vm::ptr<u32>::make(faddr + ref->addend);
const u32 raddr = ref->addr;
const u32 rtype = ref->type;
const u32 rdata = faddr + ref->addend;
const auto addr = faddr + ref->addend;
if (out_relocs)
{
// Register relocation with unpredictable target (data=0)
ppu_reloc _rel;
_rel.addr = raddr;
_rel.type = rtype;
_rel.data = 0;
out_relocs->emplace_back(_rel);
}
// OPs are probably similar to relocations
switch (u32 type = ref->type)
// OPs must be similar to relocations
switch (rtype)
{
case 0x1:
case 1:
{
const u32 value = vm::_ref<u32>(ref->addr) = addr;
const u32 value = vm::_ref<u32>(ref->addr) = rdata;
LOG_TRACE(LOADER, "**** REF(1): 0x%x <- 0x%x", ref->addr, value);
break;
}
case 0x4:
case 4:
{
const u16 value = vm::_ref<u16>(ref->addr) = static_cast<u16>(addr);
const u16 value = vm::_ref<u16>(ref->addr) = static_cast<u16>(rdata);
LOG_TRACE(LOADER, "**** REF(4): 0x%x <- 0x%04x (0x%llx)", ref->addr, value, faddr);
break;
}
case 0x6:
case 6:
{
const u16 value = vm::_ref<u16>(ref->addr) = static_cast<u16>(addr >> 16) + (addr & 0x8000 ? 1 : 0);
const u16 value = vm::_ref<u16>(ref->addr) = static_cast<u16>(rdata >> 16) + (rdata & 0x8000 ? 1 : 0);
LOG_TRACE(LOADER, "**** REF(6): 0x%x <- 0x%04x (0x%llx)", ref->addr, value, faddr);
break;
}
case 57:
{
const u16 value = vm::_ref<ppu_bf_t<be_t<u16>, 0, 14>>(ref->addr) = static_cast<u16>(addr) >> 2;
const u16 value = vm::_ref<ppu_bf_t<be_t<u16>, 0, 14>>(ref->addr) = static_cast<u16>(rdata) >> 2;
LOG_TRACE(LOADER, "**** REF(57): 0x%x <- 0x%04x (0x%llx)", ref->addr, value, faddr);
break;
}
default: LOG_ERROR(LOADER, "**** REF(%u): Unknown/Illegal type (0x%x, 0x%x)", ref->type, ref->addr, ref->addend);
default: LOG_ERROR(LOADER, "**** REF(%u): Unknown/Illegal type (0x%x, 0x%x)", rtype, raddr, ref->addend);
}
}
}
@ -523,9 +532,9 @@ static auto ppu_load_exports(const std::shared_ptr<ppu_linkage_info>& link, u32
//LOG_WARNING(LOADER, "Exported function '%s' in module '%s'", ppu_get_function_name(module_name, fnid), module_name);
}
for (const u32 weak_import_addr : flink.weak_imports)
for (const u32 fref : flink.frefss)
{
ppu_patch_refs(weak_import_addr, faddr);
ppu_patch_refs(nullptr, fref, faddr);
}
}
}
@ -557,7 +566,7 @@ static auto ppu_load_exports(const std::shared_ptr<ppu_linkage_info>& link, u32
// Fix imports
for (const auto vref : vlink.imports)
{
ppu_patch_refs(vref, vaddr);
ppu_patch_refs(nullptr, vref, vaddr);
//LOG_WARNING(LOADER, "Exported variable '%s' in module '%s'", ppu_get_variable_name(module_name, vnid), module_name);
}
}
@ -569,7 +578,7 @@ static auto ppu_load_exports(const std::shared_ptr<ppu_linkage_info>& link, u32
return result;
}
static void ppu_load_imports(const std::shared_ptr<ppu_linkage_info>& link, u32 imports_start, u32 imports_end)
static void ppu_load_imports(std::vector<ppu_reloc>& relocs, const std::shared_ptr<ppu_linkage_info>& link, u32 imports_start, u32 imports_end)
{
for (u32 addr = imports_start; addr < imports_end;)
{
@ -577,7 +586,7 @@ static void ppu_load_imports(const std::shared_ptr<ppu_linkage_info>& link, u32
const std::string module_name(lib.name.get_ptr());
LOG_NOTICE(LOADER, "** Imported module '%s' (0x%x, 0x%x)", module_name, lib.unk4, lib.unk5);
LOG_NOTICE(LOADER, "** Imported module '%s' (ver=0x%x, attr=0x%x, 0x%x, 0x%x) [0x%x]", module_name, lib.version, lib.attributes, lib.unk4, lib.unk5, addr);
if (lib.num_tlsvar)
{
@ -607,21 +616,17 @@ static void ppu_load_imports(const std::shared_ptr<ppu_linkage_info>& link, u32
flink.imports.emplace(faddr);
mlink.imported = true;
// Link if available
if (flink.export_addr)
{
vm::write32(faddr, flink.export_addr);
}
else
{
vm::write32(faddr, ppu_function_manager::addr);
}
// Link address (special HLE function by default)
const u32 link_addr = flink.export_addr ? flink.export_addr : ppu_function_manager::addr;
//weak imports, possibly
if (((lib.attributes & 0x2000) == 0x2000) && fnids[i + lib.num_func] != 0) //0x2000 seems to be correct flag
// Write import table
vm::write32(faddr, link_addr);
// Patch refs if necessary (0x2000 seems to be correct flag indicating the presence of additional info)
if (const u32 frefs = (lib.attributes & 0x2000) ? +fnids[i + lib.num_func] : 0)
{
flink.weak_imports.emplace(fnids[i + lib.num_func]);
ppu_patch_refs(fnids[i + lib.num_func], flink.export_addr);
flink.frefss.emplace(frefs);
ppu_patch_refs(&relocs, frefs, link_addr);
}
//LOG_WARNING(LOADER, "Imported function '%s' in module '%s' (0x%x)", ppu_get_function_name(module_name, fnid), module_name, faddr);
@ -644,10 +649,7 @@ static void ppu_load_imports(const std::shared_ptr<ppu_linkage_info>& link, u32
mlink.imported = true;
// Link if available
if (vlink.export_addr)
{
ppu_patch_refs(vref, vlink.export_addr);
}
ppu_patch_refs(&relocs, vref, vlink.export_addr);
//LOG_WARNING(LOADER, "Imported variable '%s' in module '%s' (0x%x)", ppu_get_variable_name(module_name, vnid), module_name, vlink.first);
}
@ -656,10 +658,13 @@ static void ppu_load_imports(const std::shared_ptr<ppu_linkage_info>& link, u32
}
}
std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::string& name)
std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::string& path)
{
std::vector<std::pair<u32, u32>> segments;
std::vector<std::pair<u32, u32>> sections;
// Create new PRX object
const auto prx = idm::make_ptr<lv2_obj, lv2_prx>();
// Access linkage information object
const auto link = fxm::get_always<ppu_linkage_info>();
for (const auto& prog : elf.progs)
{
@ -693,7 +698,12 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
ppu_register_range(addr, mem_size);
}
segments.emplace_back(std::make_pair(addr, mem_size));
ppu_segment _seg;
_seg.addr = addr;
_seg.size = mem_size;
_seg.type = p_type;
_seg.flags = prog.p_flags;
prx->segs.emplace_back(_seg);
}
break;
@ -714,13 +724,18 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
if (s.sh_type == 1 && addr && size) // TODO: some sections with addr=0 are valid
{
for (auto i = 0; i < segments.size(); i++)
for (auto i = 0; i < prx->segs.size(); i++)
{
const u32 saddr = static_cast<u32>(elf.progs[i].p_vaddr);
if (addr >= saddr && addr < saddr + elf.progs[i].p_memsz)
{
// "Relocate" section
sections.emplace_back(std::make_pair(addr - saddr + segments[i].first, size));
ppu_segment _sec;
_sec.addr = addr - saddr + prx->segs[i].addr;
_sec.size = size;
_sec.type = s.sh_type;
_sec.flags = s.sh_flags & 7;
prx->secs.emplace_back(_sec);
break;
}
}
@ -749,10 +764,13 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
{
const auto& rel = reinterpret_cast<const ppu_prx_relocation_info&>(prog.bin[i]);
const u32 raddr = vm::cast(segments.at(rel.index_addr).first + rel.offset, HERE);
const u64 rdata = segments.at(rel.index_value).first + rel.ptr.addr();
ppu_reloc _rel;
const u32 raddr = _rel.addr = vm::cast(prx->segs.at(rel.index_addr).addr + rel.offset, HERE);
const u32 rtype = _rel.type = rel.type;
const u64 rdata = _rel.data = prx->segs.at(rel.index_value).addr + rel.ptr.addr();
prx->relocs.emplace_back(_rel);
switch (const u32 type = rel.type)
switch (rtype)
{
case 1: // R_PPC64_ADDR32
{
@ -817,7 +835,12 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
break;
}
default: LOG_ERROR(LOADER, "**** RELOCATION(%u): Illegal/Unknown type! (addr=0x%x; 0x%llx)", type, raddr, rdata);
default: LOG_ERROR(LOADER, "**** RELOCATION(%u): Illegal/Unknown type! (addr=0x%x; 0x%llx)", rtype, raddr, rdata);
}
if (rdata == 0)
{
LOG_TODO(LOADER, "**** RELOCATION(%u): 0x%x <- (zero-based value)", rtype, raddr);
}
}
@ -826,12 +849,6 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
}
}
// Access linkage information object
const auto link = fxm::get_always<ppu_linkage_info>();
// Create new PRX object
auto prx = idm::make_ptr<lv2_obj, lv2_prx>();
if (!elf.progs.empty() && elf.progs[0].p_paddr)
{
struct ppu_prx_library_info
@ -847,16 +864,16 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
};
// Access library information (TODO)
const auto& lib_info = vm::cptr<ppu_prx_library_info>(vm::cast(segments[0].first + elf.progs[0].p_paddr - elf.progs[0].p_offset, HERE));
const auto& lib_info = vm::cptr<ppu_prx_library_info>(vm::cast(prx->segs[0].addr + elf.progs[0].p_paddr - elf.progs[0].p_offset, HERE));
const auto& lib_name = std::string(lib_info->name);
LOG_WARNING(LOADER, "Library %s (rtoc=0x%x):", lib_name, lib_info->toc);
prx->specials = ppu_load_exports(link, lib_info->exports_start, lib_info->exports_end);
ppu_load_imports(link, lib_info->imports_start, lib_info->imports_end);
ppu_load_imports(prx->relocs, link, lib_info->imports_start, lib_info->imports_end);
prx->funcs = ppu_analyse(segments, sections, lib_info->toc, 0);
prx->analyse(lib_info->toc, 0);
}
else
{
@ -868,7 +885,8 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
prx->exit.set(prx->specials[0x3ab9a95e]);
prx->prologue.set(prx->specials[0x0D10FD3F]);
prx->epilogue.set(prx->specials[0x330F7005]);
prx->name = name;
prx->name = path.substr(path.find_last_of('/') + 1);
prx->path = path;
return prx;
}
@ -879,15 +897,12 @@ void ppu_load_exec(const ppu_exec_object& elf)
LOG_TODO(LOADER, "'Hook static functions' option deactivated");
}
// Set for delayed initialization in ppu_initialize()
const auto _main = fxm::make<ppu_module>();
// Access linkage information object
const auto link = fxm::get_always<ppu_linkage_info>();
// Segment info
std::vector<std::pair<u32, u32>> segments;
// Section info (optional)
std::vector<std::pair<u32, u32>> sections;
// TLS information
u32 tls_vaddr = 0;
u32 tls_fsize = 0;
@ -904,10 +919,13 @@ void ppu_load_exec(const ppu_exec_object& elf)
{
LOG_NOTICE(LOADER, "** Segment: p_type=0x%x, p_vaddr=0x%llx, p_filesz=0x%llx, p_memsz=0x%llx, flags=0x%x", prog.p_type, prog.p_vaddr, prog.p_filesz, prog.p_memsz, prog.p_flags);
const u32 addr = vm::cast(prog.p_vaddr, HERE);
const u32 size = ::narrow<u32>(prog.p_memsz, "p_memsz" HERE);
if (prog.p_type == 0x1 /* LOAD */ && prog.p_memsz)
ppu_segment _seg;
const u32 addr = _seg.addr = vm::cast(prog.p_vaddr, HERE);
const u32 size = _seg.size = ::narrow<u32>(prog.p_memsz, "p_memsz" HERE);
const u32 type = _seg.type = prog.p_type;
const u32 flag = _seg.flags = prog.p_flags;
if (type == 0x1 /* LOAD */ && prog.p_memsz)
{
if (prog.bin.size() > size || prog.bin.size() != prog.p_filesz)
fmt::throw_exception("Invalid binary size (0x%llx, memsz=0x%x)", prog.bin.size(), size);
@ -924,7 +942,8 @@ void ppu_load_exec(const ppu_exec_object& elf)
ppu_register_range(addr, size);
}
segments.emplace_back(std::make_pair(addr, size));
// Store only LOAD segments (TODO)
_main->segs.emplace_back(_seg);
}
}
@ -933,12 +952,15 @@ void ppu_load_exec(const ppu_exec_object& elf)
{
LOG_NOTICE(LOADER, "** Section: sh_type=0x%x, addr=0x%llx, size=0x%llx, flags=0x%x", s.sh_type, s.sh_addr, s.sh_size, s.sh_flags);
const u32 addr = vm::cast(s.sh_addr);
const u32 size = vm::cast(s.sh_size);
ppu_segment _sec;
const u32 addr = _sec.addr = vm::cast(s.sh_addr);
const u32 size = _sec.size = vm::cast(s.sh_size);
const u32 type = _sec.type = s.sh_type;
const u32 flag = _sec.flags = s.sh_flags & 7;
if (s.sh_type == 1 && addr && size)
{
sections.emplace_back(std::make_pair(addr, size));
_main->secs.emplace_back(_sec);
}
}
@ -1038,7 +1060,7 @@ void ppu_load_exec(const ppu_exec_object& elf)
}
ppu_load_exports(link, proc_prx_param.libent_start, proc_prx_param.libent_end);
ppu_load_imports(link, proc_prx_param.libstub_start, proc_prx_param.libstub_end);
ppu_load_imports(_main->relocs, link, proc_prx_param.libstub_start, proc_prx_param.libstub_end);
}
break;
}
@ -1209,7 +1231,7 @@ void ppu_load_exec(const ppu_exec_object& elf)
{
LOG_WARNING(LOADER, "Loading library: %s", name);
auto prx = ppu_load_prx(obj, name);
auto prx = ppu_load_prx(obj, lle_dir + name);
if (prx->funcs.empty())
{
@ -1218,7 +1240,7 @@ void ppu_load_exec(const ppu_exec_object& elf)
else
{
// TODO: fix arguments
ppu_validate(lle_dir + name, prx->funcs, prx->funcs[0].addr);
prx->validate(prx->funcs[0].addr);
}
loaded_modules.emplace_back(std::move(prx));
@ -1230,17 +1252,15 @@ void ppu_load_exec(const ppu_exec_object& elf)
}
}
{
// Analyse executable (TODO)
ppu_module _main;
_main.funcs = ppu_analyse(segments, sections, 0, elf.header.e_entry);
// Set path (TODO)
_main->name = "";
_main->path = vfs::get(Emu.GetPath());
// Validate analyser results (not required)
ppu_validate(vfs::get(Emu.GetPath()), _main.funcs, 0);
// Analyse executable (TODO)
_main->analyse(0, static_cast<u32>(elf.header.e_entry));
// Set for delayed initialization in ppu_initialize()
fxm::make<ppu_module>(std::move(_main));
}
// Validate analyser results (not required)
_main->validate(0);
// Set SDK version
g_ps3_sdk_version = sdk_version;
@ -1262,7 +1282,7 @@ void ppu_load_exec(const ppu_exec_object& elf)
*argv++ = arg_addr;
}
argv -= args.size();
argv -= ::size32(args);
// Initialize main thread
auto ppu = idm::make_ptr<ppu_thread>("main_thread", primary_prio, primary_stacksize);

View File

@ -982,24 +982,31 @@ extern void ppu_initialize(const ppu_module& info)
// Worker threads
std::vector<std::thread> jthreads;
// Global variables (pointers) to initialize
std::vector<std::pair<std::string, void*>> globals;
// Global variables to initialize
std::vector<std::pair<std::string, u64>> globals;
// Split module into fragments <= 1 MiB
std::size_t fpos = 0;
// Copy module information
ppu_module part = info;
// Difference between function name and current location
const u32 reloc = info.name.empty() ? 0 : info.segs.at(0).addr;
while (fpos < info.funcs.size())
{
// First function in current module part
const auto fstart = fpos;
std::size_t bsize = 0;
// Copy module information (TODO: optimize)
ppu_module part = info;
part.funcs.clear();
part.funcs.reserve(16000);
// Unique suffix for each module part
const u32 suffix = info.funcs.at(fstart).addr - reloc;
// Overall block size in bytes
std::size_t bsize = 0;
while (fpos < info.funcs.size())
{
auto& func = info.funcs[fpos];
@ -1018,28 +1025,28 @@ extern void ppu_initialize(const ppu_module& info)
entry.addr = block.first;
entry.size = block.second;
entry.toc = func.toc;
fmt::append(entry.name, "__0x%x", block.first);
fmt::append(entry.name, "__0x%x", block.first - reloc);
part.funcs.emplace_back(std::move(entry));
}
fpos++;
}
part.name.clear();
// Version, module name and hash: vX-liblv2.sprx-0123456789ABCDEF.obj
std::string obj_name = "v2";
if (info.name.size())
{
part.name += '-';
part.name += info.name;
obj_name += '-';
obj_name += info.name;
}
if (fstart || fpos < info.funcs.size())
{
fmt::append(part.name, "+%06X", info.funcs.at(fstart).addr);
fmt::append(obj_name, "+%06X", suffix);
}
// Compute module hash
std::string obj_name;
{
sha1_context ctx;
u8 output[20];
@ -1052,28 +1059,32 @@ extern void ppu_initialize(const ppu_module& info)
continue;
}
const be_t<u32> addr = func.addr;
const be_t<u32> addr = func.addr - reloc;
const be_t<u32> size = func.size;
sha1_update(&ctx, reinterpret_cast<const u8*>(&addr), sizeof(addr));
sha1_update(&ctx, reinterpret_cast<const u8*>(&size), sizeof(size));
for (const auto& block : func.blocks)
{
if (block.second == 0)
if (block.second == 0 || reloc)
{
continue;
}
// TODO: relocations must be taken into account (TODO)
sha1_update(&ctx, vm::ps3::_ptr<const u8>(block.first), block.second);
}
if (reloc)
{
continue;
}
sha1_update(&ctx, vm::ps3::_ptr<const u8>(func.addr), func.size);
}
sha1_finish(&ctx, output);
// Version, module name and hash: vX-liblv2.sprx-0123456789ABCDEF.obj
fmt::append(obj_name, "v2%s-%016X-%s.obj", part.name, reinterpret_cast<be_t<u64>&>(output), jit.cpu());
fmt::append(obj_name, "-%016X-%s.obj", reinterpret_cast<be_t<u64>&>(output), jit.cpu());
}
if (Emu.IsStopped())
@ -1081,19 +1092,49 @@ extern void ppu_initialize(const ppu_module& info)
break;
}
globals.emplace_back(fmt::format("__mptr%x", part.funcs[0].addr), vm::g_base_addr);
globals.emplace_back(fmt::format("__cptr%x", part.funcs[0].addr), vm::g_exec_addr);
globals.emplace_back(fmt::format("__mptr%x", suffix), (u64)vm::g_base_addr);
globals.emplace_back(fmt::format("__cptr%x", suffix), (u64)vm::g_exec_addr);
// Initialize segments for relocations
for (u32 i = 0; i < info.segs.size(); i++)
{
globals.emplace_back(fmt::format("__seg%u_%x", i, suffix), info.segs[i].addr);
}
// Get cache path for this executable
std::string cache_path;
if (info.name.empty())
{
cache_path = Emu.GetCachePath();
}
else
{
cache_path = vfs::get("/dev_flash/");
if (info.path.compare(0, cache_path.size(), cache_path) == 0)
{
// Remove prefix for dev_flash files
cache_path.clear();
}
else
{
cache_path = Emu.GetTitleID();
}
cache_path = fs::get_data_dir(cache_path, info.path);
}
// Check object file
if (fs::is_file(Emu.GetCachePath() + obj_name))
if (fs::is_file(cache_path + obj_name))
{
semaphore_lock lock(jmutex);
ppu_initialize2(jit, part, Emu.GetCachePath(), obj_name);
ppu_initialize2(jit, part, cache_path, obj_name);
continue;
}
// Create worker thread for compilation
jthreads.emplace_back([&jit, &jmutex, &jcores, obj_name = obj_name, part = std::move(part)]()
jthreads.emplace_back([&jit, &jmutex, &jcores, obj_name = obj_name, part = std::move(part), cache_path = std::move(cache_path)]()
{
// Set low priority
thread_ctrl::set_native_priority(-1);
@ -1109,17 +1150,17 @@ extern void ppu_initialize(const ppu_module& info)
// Use another JIT instance
jit_compiler jit2({}, g_cfg.core.llvm_cpu);
ppu_initialize2(jit2, part, Emu.GetCachePath(), obj_name);
ppu_initialize2(jit2, part, cache_path, obj_name);
}
if (Emu.IsStopped())
if (Emu.IsStopped() || !fs::is_file(cache_path + obj_name))
{
return;
}
// Proceed with original JIT instance
semaphore_lock lock(jmutex);
ppu_initialize2(jit, part, Emu.GetCachePath(), obj_name);
ppu_initialize2(jit, part, cache_path, obj_name);
});
}
@ -1145,7 +1186,7 @@ extern void ppu_initialize(const ppu_module& info)
{
if (block.second)
{
ppu_ref(block.first) = ::narrow<u32>(jit.get(fmt::format("__0x%x", block.first)));
ppu_ref(block.first) = ::narrow<u32>(jit.get(fmt::format("__0x%x", block.first - reloc)));
}
}
}
@ -1155,7 +1196,7 @@ extern void ppu_initialize(const ppu_module& info)
{
if (u64 addr = jit.get(var.first))
{
*reinterpret_cast<void**>(addr) = var.second;
*reinterpret_cast<u64*>(addr) = var.second;
}
}
#endif
@ -1256,10 +1297,16 @@ static void ppu_initialize2(jit_compiler& jit, const ppu_module& module_part, co
});
// Translate
const auto func = translator.Translate(module_part.funcs[fi]);
// Run optimization passes
pm.run(*func);
if (const auto func = translator.Translate(module_part.funcs[fi]))
{
// Run optimization passes
pm.run(*func);
}
else
{
Emu.Pause();
return;
}
}
}

View File

@ -1,4 +1,4 @@
#ifdef LLVM_AVAILABLE
#ifdef LLVM_AVAILABLE
#include "PPUTranslator.h"
#include "PPUThread.h"
@ -18,8 +18,11 @@ PPUTranslator::PPUTranslator(LLVMContext& context, Module* module, const ppu_mod
, m_info(info)
, m_pure_attr(AttributeSet::get(m_context, AttributeSet::FunctionIndex, {Attribute::NoUnwind, Attribute::ReadNone}))
{
// There is no weak linkage on JIT, so let's create variables with different names for each module part
const u32 gsuffix = m_info.name.empty() ? info.funcs[0].addr : info.funcs[0].addr - m_info.segs[0].addr;
// Memory base
m_base = new GlobalVariable(*module, ArrayType::get(GetType<char>(), 0x100000000)->getPointerTo(), true, GlobalValue::ExternalLinkage, 0, fmt::format("__mptr%x", info.funcs[0].addr));
m_base = new GlobalVariable(*module, ArrayType::get(GetType<char>(), 0x100000000)->getPointerTo(), true, GlobalValue::ExternalLinkage, 0, fmt::format("__mptr%x", gsuffix));
m_base->setInitializer(ConstantPointerNull::get(cast<PointerType>(m_base->getType()->getPointerElementType())));
m_base->setExternallyInitialized(true);
@ -44,7 +47,7 @@ PPUTranslator::PPUTranslator(LLVMContext& context, Module* module, const ppu_mod
m_thread_type = StructType::create(m_context, thread_struct, "context_t");
// Callable
m_call = new GlobalVariable(*module, ArrayType::get(GetType<u32>(), 0x40000000)->getPointerTo(), true, GlobalValue::ExternalLinkage, 0, fmt::format("__cptr%x", info.funcs[0].addr));
m_call = new GlobalVariable(*module, ArrayType::get(GetType<u32>(), 0x40000000)->getPointerTo(), true, GlobalValue::ExternalLinkage, 0, fmt::format("__cptr%x", gsuffix));
m_call->setInitializer(ConstantPointerNull::get(cast<PointerType>(m_call->getType()->getPointerElementType())));
m_call->setExternallyInitialized(true);
@ -55,6 +58,56 @@ PPUTranslator::PPUTranslator(LLVMContext& context, Module* module, const ppu_mod
// Metadata for branch weights
m_md_likely = MDTuple::get(m_context, {md_name, md_high, md_low});
m_md_unlikely = MDTuple::get(m_context, {md_name, md_low, md_high});
// Create segment variables
for (const auto& seg : m_info.segs)
{
auto gv = new GlobalVariable(*module, GetType<u64>(), true, GlobalValue::ExternalLinkage, 0, fmt::format("__seg%u_%x", m_segs.size(), gsuffix));
gv->setInitializer(ConstantInt::get(GetType<u64>(), seg.addr));
gv->setExternallyInitialized(true);
m_segs.emplace_back(gv);
}
// Sort relevant relocations (TODO)
const auto caddr = m_info.segs[0].addr;
const auto cend = caddr + m_info.segs[0].size;
for (const auto& rel : m_info.relocs)
{
if (rel.addr >= caddr && rel.addr < cend)
{
// Check relocation type
switch (rel.type)
{
case 20:
case 22:
case 38:
case 43:
case 44:
case 45:
case 46:
case 51:
case 68:
case 73:
case 78:
{
LOG_ERROR(PPU, "64-bit relocation at 0x%x (%u)", rel.addr, rel.type);
continue;
}
}
// Align relocation address (TODO)
if (!m_relocs.emplace(rel.addr & ~3, &rel).second)
{
LOG_ERROR(PPU, "Relocation repeated at 0x%x (%u)", rel.addr, rel.type);
}
}
}
if (!m_info.name.empty())
{
m_reloc = &m_info.segs[0];
}
}
PPUTranslator::~PPUTranslator()
@ -69,8 +122,6 @@ Type* PPUTranslator::GetContextType()
Function* PPUTranslator::Translate(const ppu_function& info)
{
m_function = m_module->getFunction(info.name);
m_start_addr = info.addr;
m_end_addr = info.addr + info.size;
std::fill(std::begin(m_globals), std::end(m_globals), nullptr);
std::fill(std::begin(m_locals), std::end(m_locals), nullptr);
@ -78,6 +129,10 @@ Function* PPUTranslator::Translate(const ppu_function& info)
IRBuilder<> irb(m_entry = BasicBlock::Create(m_context, "__entry", m_function));
m_ir = &irb;
// Instruction address is (m_addr + base)
const u64 base = m_reloc ? m_reloc->addr : 0;
m_addr = info.addr - base;
m_thread = &*m_function->getArgumentList().begin();
m_base_loaded = m_ir->CreateLoad(m_base);
@ -90,7 +145,7 @@ Function* PPUTranslator::Translate(const ppu_function& info)
// Create tail call to the check function
m_ir->SetInsertPoint(vcheck);
Call(GetType<void>(), "__check", m_thread, m_ir->getInt64(m_start_addr))->setTailCallKind(llvm::CallInst::TCK_Tail);
Call(GetType<void>(), "__check", m_thread, GetAddr())->setTailCallKind(llvm::CallInst::TCK_Tail);
m_ir->CreateRetVoid();
m_ir->SetInsertPoint(m_body);
@ -104,28 +159,58 @@ Function* PPUTranslator::Translate(const ppu_function& info)
}
// Process the instructions
for (m_current_addr = block.first; m_current_addr < block.first + block.second; m_current_addr += 4)
for (m_addr = block.first - base; m_addr < block.first + block.second - base; m_addr += 4)
{
if (m_body->getTerminator())
{
break;
}
const u32 op = vm::ps3::read32(vm::cast(m_current_addr));
// Find the relocation at current address
const auto rel_found = m_relocs.find(m_addr + base);
if (rel_found != m_relocs.end())
{
m_rel = rel_found->second;
}
else
{
m_rel = nullptr;
}
const u32 op = vm::ps3::read32(vm::cast(m_addr + base));
(this->*(s_ppu_decoder.decode(op)))({op});
if (m_rel)
{
// This is very bæd
LOG_ERROR(PPU, "LLVM: [0x%x] Unsupported relocation(%u) in '%s'. Please report.", rel_found->first, m_rel->type, m_info.name);
return nullptr;
}
}
// Finalize current block if necessary (create branch to the next address)
if (!m_body->getTerminator())
{
FlushRegisters();
CallFunction(m_current_addr);
CallFunction(m_addr);
}
}
return m_function;
}
Value* PPUTranslator::GetAddr(u64 _add)
{
if (m_reloc)
{
// Load segment address from global variable, compute actual instruction address
return m_ir->CreateAdd(m_ir->getInt64(m_addr + _add), m_ir->CreateLoad(m_segs[m_reloc - m_info.segs.data()]));
}
return m_ir->getInt64(m_addr + _add);
}
Type* PPUTranslator::ScaleType(Type* type, s32 pow2)
{
verify(HERE), (type->getScalarType()->isIntegerTy());
@ -159,9 +244,9 @@ void PPUTranslator::CallFunction(u64 target, Value* indirect)
if (!indirect)
{
if (target < 0x10000 || target >= -0x10000)
if ((!m_reloc && target < 0x10000) || target >= -0x10000)
{
Trap(m_current_addr);
Trap();
return;
}
@ -414,11 +499,11 @@ void PPUTranslator::UseCondition(MDNode* hint, Value* cond)
if (cond)
{
const auto local = BasicBlock::Create(m_context, fmt::format("loc_%llx.cond", m_current_addr), m_function);
const auto next = BasicBlock::Create(m_context, fmt::format("loc_%llx.next", m_current_addr), m_function);
const auto local = BasicBlock::Create(m_context, "__cond", m_function);
const auto next = BasicBlock::Create(m_context, "__next", m_function);
m_ir->CreateCondBr(cond, local, next, hint);
m_ir->SetInsertPoint(next);
CallFunction(m_current_addr + 4);
CallFunction(m_addr + 4);
m_ir->SetInsertPoint(local);
}
}
@ -462,7 +547,7 @@ void PPUTranslator::WriteMemory(Value* addr, Value* value, bool is_be, u32 align
void PPUTranslator::CompilationError(const std::string& error)
{
LOG_ERROR(PPU, "[0x%08llx] 0x%08llx: Error: %s", m_start_addr, m_current_addr, error);
LOG_ERROR(PPU, "LLVM: [0x%08x] Error: %s", m_addr + (m_reloc ? m_reloc->addr : 0), error);
}
@ -1535,13 +1620,13 @@ void PPUTranslator::VXOR(ppu_opcode_t op)
void PPUTranslator::TDI(ppu_opcode_t op)
{
UseCondition(m_md_unlikely, CheckTrapCondition(op.bo, GetGpr(op.ra), m_ir->getInt64(op.simm16)));
Trap(m_current_addr);
Trap();
}
void PPUTranslator::TWI(ppu_opcode_t op)
{
UseCondition(m_md_unlikely, CheckTrapCondition(op.bo, GetGpr(op.ra, 32), m_ir->getInt32(op.simm16)));
Trap(m_current_addr);
Trap();
}
void PPUTranslator::MULLI(ppu_opcode_t op)
@ -1570,8 +1655,15 @@ void PPUTranslator::CMPI(ppu_opcode_t op)
void PPUTranslator::ADDIC(ppu_opcode_t op)
{
Value* imm = m_ir->getInt64(op.simm16);
if (m_rel && m_rel->type == 4)
{
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
m_rel = nullptr;
}
const auto a = GetGpr(op.ra);
const auto imm = m_ir->getInt64(op.simm16);
const auto result = m_ir->CreateAdd(a, imm);
SetGpr(op.rd, result);
SetCarry(m_ir->CreateICmpULT(result, imm));
@ -1580,25 +1672,44 @@ void PPUTranslator::ADDIC(ppu_opcode_t op)
void PPUTranslator::ADDI(ppu_opcode_t op)
{
const auto imm = m_ir->getInt64(op.simm16);
Value* imm = m_ir->getInt64(op.simm16);
if (m_rel && m_rel->type == 4)
{
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
m_rel = nullptr;
}
SetGpr(op.rd, op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm);
}
void PPUTranslator::ADDIS(ppu_opcode_t op)
{
const auto imm = m_ir->getInt64(op.simm16 << 16);
Value* imm = m_ir->getInt64(op.simm16 << 16);
if (m_rel && m_rel->type == 6)
{
imm = m_ir->CreateShl(SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>()), 16);
m_rel = nullptr;
}
SetGpr(op.rd, op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm);
}
void PPUTranslator::BC(ppu_opcode_t op)
{
const u64 target = (op.aa ? 0 : m_current_addr) + op.bt14;
const u64 target = (op.aa ? 0 : m_addr) + op.bt14;
if (op.aa && m_reloc)
{
CompilationError("Branch with absolute address");
}
UseCondition(CheckBranchProbability(op.bo), CheckBranchCondition(op.bo, op.bi));
if (op.lk)
{
m_ir->CreateStore(m_ir->getInt64(m_current_addr + 4), m_ir->CreateStructGEP(nullptr, m_thread, &m_lr - m_locals));
m_ir->CreateStore(GetAddr(+4), m_ir->CreateStructGEP(nullptr, m_thread, &m_lr - m_locals));
}
CallFunction(target);
@ -1612,7 +1723,7 @@ void PPUTranslator::SC(ppu_opcode_t op)
}
const auto num = GetGpr(11);
RegStore(m_ir->getInt32(m_current_addr), m_cia);
RegStore(Trunc(GetAddr()), m_cia);
FlushRegisters();
if (!op.lev && isa<ConstantInt>(num))
@ -1635,11 +1746,16 @@ void PPUTranslator::SC(ppu_opcode_t op)
void PPUTranslator::B(ppu_opcode_t op)
{
const u64 target = (op.aa ? 0 : m_current_addr) + op.bt24;
const u64 target = (op.aa ? 0 : m_addr) + op.bt24;
if (op.aa && m_reloc)
{
CompilationError("Branch with absolute address");
}
if (op.lk)
{
RegStore(m_ir->getInt64(m_current_addr + 4), m_lr);
RegStore(GetAddr(+4), m_lr);
}
FlushRegisters();
@ -1663,7 +1779,7 @@ void PPUTranslator::BCLR(ppu_opcode_t op)
if (op.lk)
{
m_ir->CreateStore(m_ir->getInt64(m_current_addr + 4), m_ir->CreateStructGEP(nullptr, m_thread, &m_lr - m_locals));
m_ir->CreateStore(GetAddr(+4), m_ir->CreateStructGEP(nullptr, m_thread, &m_lr - m_locals));
}
CallFunction(0, target);
@ -1726,7 +1842,7 @@ void PPUTranslator::BCCTR(ppu_opcode_t op)
if (op.lk)
{
m_ir->CreateStore(m_ir->getInt64(m_current_addr + 4), m_ir->CreateStructGEP(nullptr, m_thread, &m_lr - m_locals));
m_ir->CreateStore(GetAddr(+4), m_ir->CreateStructGEP(nullptr, m_thread, &m_lr - m_locals));
}
CallFunction(0, target);
@ -1870,12 +1986,34 @@ void PPUTranslator::RLWNM(ppu_opcode_t op)
void PPUTranslator::ORI(ppu_opcode_t op)
{
SetGpr(op.ra, m_ir->CreateOr(GetGpr(op.rs), op.uimm16));
Value* imm = m_ir->getInt64(op.uimm16);
if (m_rel && m_rel->type == 4)
{
imm = ZExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
m_rel = nullptr;
}
SetGpr(op.ra, m_ir->CreateOr(GetGpr(op.rs), imm));
}
void PPUTranslator::ORIS(ppu_opcode_t op)
{
SetGpr(op.ra, m_ir->CreateOr(GetGpr(op.rs), op.uimm16 << 16));
Value* imm = m_ir->getInt64(op.uimm16 << 16);
if (m_rel && m_rel->type == 5)
{
imm = m_ir->CreateShl(ZExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>()), 16);
m_rel = nullptr;
}
if (m_rel && m_rel->type == 6)
{
imm = m_ir->CreateShl(ZExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>()), 16);
m_rel = nullptr;
}
SetGpr(op.ra, m_ir->CreateOr(GetGpr(op.rs), imm));
}
void PPUTranslator::XORI(ppu_opcode_t op)
@ -2050,7 +2188,7 @@ void PPUTranslator::TW(ppu_opcode_t op)
FlushRegisters();
}
Trap(m_current_addr);
Trap();
}
void PPUTranslator::LVSL(ppu_opcode_t op)
@ -2266,7 +2404,7 @@ void PPUTranslator::ANDC(ppu_opcode_t op)
void PPUTranslator::TD(ppu_opcode_t op)
{
UseCondition(m_md_unlikely, CheckTrapCondition(op.bo, GetGpr(op.ra), GetGpr(op.rb)));
Trap(m_current_addr);
Trap();
}
void PPUTranslator::LVEWX(ppu_opcode_t op)
@ -3136,84 +3274,196 @@ void PPUTranslator::DCBZ(ppu_opcode_t op)
void PPUTranslator::LWZ(ppu_opcode_t op)
{
SetGpr(op.rd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16)) : m_ir->getInt64(op.simm16), GetType<u32>()));
Value* imm = m_ir->getInt64(op.simm16);
if (m_rel && m_rel->type == 4)
{
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
m_rel = nullptr;
}
SetGpr(op.rd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetType<u32>()));
}
void PPUTranslator::LWZU(ppu_opcode_t op)
{
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16));
Value* imm = m_ir->getInt64(op.simm16);
if (m_rel && m_rel->type == 4)
{
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
m_rel = nullptr;
}
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
SetGpr(op.rd, ReadMemory(addr, GetType<u32>()));
SetGpr(op.ra, addr);
}
void PPUTranslator::LBZ(ppu_opcode_t op)
{
SetGpr(op.rd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16)) : m_ir->getInt64(op.simm16), GetType<u8>()));
Value* imm = m_ir->getInt64(op.simm16);
if (m_rel && m_rel->type == 4)
{
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
m_rel = nullptr;
}
SetGpr(op.rd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetType<u8>()));
}
void PPUTranslator::LBZU(ppu_opcode_t op)
{
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16));
Value* imm = m_ir->getInt64(op.simm16);
if (m_rel && m_rel->type == 4)
{
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
m_rel = nullptr;
}
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
SetGpr(op.rd, ReadMemory(addr, GetType<u8>()));
SetGpr(op.ra, addr);
}
void PPUTranslator::STW(ppu_opcode_t op)
{
WriteMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16)) : m_ir->getInt64(op.simm16), GetGpr(op.rs, 32));
Value* imm = m_ir->getInt64(op.simm16);
if (m_rel && m_rel->type == 4)
{
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
m_rel = nullptr;
}
WriteMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetGpr(op.rs, 32));
}
void PPUTranslator::STWU(ppu_opcode_t op)
{
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16));
Value* imm = m_ir->getInt64(op.simm16);
if (m_rel && m_rel->type == 4)
{
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
m_rel = nullptr;
}
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
WriteMemory(addr, GetGpr(op.rs, 32));
SetGpr(op.ra, addr);
}
void PPUTranslator::STB(ppu_opcode_t op)
{
WriteMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16)) : m_ir->getInt64(op.simm16), GetGpr(op.rs, 8));
Value* imm = m_ir->getInt64(op.simm16);
if (m_rel && m_rel->type == 4)
{
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
m_rel = nullptr;
}
WriteMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetGpr(op.rs, 8));
}
void PPUTranslator::STBU(ppu_opcode_t op)
{
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16));
Value* imm = m_ir->getInt64(op.simm16);
if (m_rel && m_rel->type == 4)
{
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
m_rel = nullptr;
}
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
WriteMemory(addr, GetGpr(op.rs, 8));
SetGpr(op.ra, addr);
}
void PPUTranslator::LHZ(ppu_opcode_t op)
{
SetGpr(op.rd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16)) : m_ir->getInt64(op.simm16), GetType<u16>()));
Value* imm = m_ir->getInt64(op.simm16);
if (m_rel && m_rel->type == 4)
{
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
m_rel = nullptr;
}
SetGpr(op.rd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetType<u16>()));
}
void PPUTranslator::LHZU(ppu_opcode_t op)
{
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16));
Value* imm = m_ir->getInt64(op.simm16);
if (m_rel && m_rel->type == 4)
{
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
m_rel = nullptr;
}
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
SetGpr(op.rd, ReadMemory(addr, GetType<u16>()));
SetGpr(op.ra, addr);
}
void PPUTranslator::LHA(ppu_opcode_t op)
{
SetGpr(op.rd, SExt(ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16)) : m_ir->getInt64(op.simm16), GetType<s16>()), GetType<s64>()));
Value* imm = m_ir->getInt64(op.simm16);
if (m_rel && m_rel->type == 4)
{
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
m_rel = nullptr;
}
SetGpr(op.rd, SExt(ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetType<s16>()), GetType<s64>()));
}
void PPUTranslator::LHAU(ppu_opcode_t op)
{
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16));
Value* imm = m_ir->getInt64(op.simm16);
if (m_rel && m_rel->type == 4)
{
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
m_rel = nullptr;
}
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
SetGpr(op.rd, SExt(ReadMemory(addr, GetType<s16>()), GetType<s64>()));
SetGpr(op.ra, addr);
}
void PPUTranslator::STH(ppu_opcode_t op)
{
WriteMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16)) : m_ir->getInt64(op.simm16), GetGpr(op.rs, 16));
Value* imm = m_ir->getInt64(op.simm16);
if (m_rel && m_rel->type == 4)
{
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
m_rel = nullptr;
}
WriteMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetGpr(op.rs, 16));
}
void PPUTranslator::STHU(ppu_opcode_t op)
{
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16));
Value* imm = m_ir->getInt64(op.simm16);
if (m_rel && m_rel->type == 4)
{
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
m_rel = nullptr;
}
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
WriteMemory(addr, GetGpr(op.rs, 16));
SetGpr(op.ra, addr);
}
@ -3236,77 +3486,181 @@ void PPUTranslator::STMW(ppu_opcode_t op)
void PPUTranslator::LFS(ppu_opcode_t op)
{
SetFpr(op.frd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16)) : m_ir->getInt64(op.simm16), GetType<f32>()));
Value* imm = m_ir->getInt64(op.simm16);
if (m_rel && m_rel->type == 4)
{
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
m_rel = nullptr;
}
SetFpr(op.frd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetType<f32>()));
}
void PPUTranslator::LFSU(ppu_opcode_t op)
{
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16));
Value* imm = m_ir->getInt64(op.simm16);
if (m_rel && m_rel->type == 4)
{
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
m_rel = nullptr;
}
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
SetFpr(op.frd, ReadMemory(addr, GetType<f32>()));
SetGpr(op.ra, addr);
}
void PPUTranslator::LFD(ppu_opcode_t op)
{
SetFpr(op.frd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16)) : m_ir->getInt64(op.simm16), GetType<f64>()));
Value* imm = m_ir->getInt64(op.simm16);
if (m_rel && m_rel->type == 4)
{
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
m_rel = nullptr;
}
SetFpr(op.frd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetType<f64>()));
}
void PPUTranslator::LFDU(ppu_opcode_t op)
{
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16));
Value* imm = m_ir->getInt64(op.simm16);
if (m_rel && m_rel->type == 4)
{
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
m_rel = nullptr;
}
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
SetFpr(op.frd, ReadMemory(addr, GetType<f64>()));
SetGpr(op.ra, addr);
}
void PPUTranslator::STFS(ppu_opcode_t op)
{
WriteMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16)) : m_ir->getInt64(op.simm16), GetFpr(op.frs, 32));
Value* imm = m_ir->getInt64(op.simm16);
if (m_rel && m_rel->type == 4)
{
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
m_rel = nullptr;
}
WriteMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetFpr(op.frs, 32));
}
void PPUTranslator::STFSU(ppu_opcode_t op)
{
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16));
Value* imm = m_ir->getInt64(op.simm16);
if (m_rel && m_rel->type == 4)
{
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
m_rel = nullptr;
}
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
WriteMemory(addr, GetFpr(op.frs, 32));
SetGpr(op.ra, addr);
}
void PPUTranslator::STFD(ppu_opcode_t op)
{
WriteMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16)) : m_ir->getInt64(op.simm16), GetFpr(op.frs));
Value* imm = m_ir->getInt64(op.simm16);
if (m_rel && m_rel->type == 4)
{
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
m_rel = nullptr;
}
WriteMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetFpr(op.frs));
}
void PPUTranslator::STFDU(ppu_opcode_t op)
{
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.simm16));
Value* imm = m_ir->getInt64(op.simm16);
if (m_rel && m_rel->type == 4)
{
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
m_rel = nullptr;
}
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
WriteMemory(addr, GetFpr(op.frs));
SetGpr(op.ra, addr);
}
void PPUTranslator::LD(ppu_opcode_t op)
{
SetGpr(op.rd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.ds << 2)) : m_ir->getInt64(op.ds << 2), GetType<u64>()));
Value* imm = m_ir->getInt64(op.ds << 2);
if (m_rel && m_rel->type == 57)
{
imm = m_ir->CreateAnd(SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>()), ~3);
m_rel = nullptr;
}
SetGpr(op.rd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetType<u64>()));
}
void PPUTranslator::LDU(ppu_opcode_t op)
{
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.ds << 2));
Value* imm = m_ir->getInt64(op.ds << 2);
if (m_rel && m_rel->type == 57)
{
imm = m_ir->CreateAnd(SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>()), ~3);
m_rel = nullptr;
}
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
SetGpr(op.rd, ReadMemory(addr, GetType<u64>()));
SetGpr(op.ra, addr);
}
void PPUTranslator::LWA(ppu_opcode_t op)
{
SetGpr(op.rd, SExt(ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.ds << 2)) : m_ir->getInt64(op.ds << 2), GetType<s32>())));
Value* imm = m_ir->getInt64(op.ds << 2);
if (m_rel && m_rel->type == 57)
{
imm = m_ir->CreateAnd(SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>()), ~3);
m_rel = nullptr;
}
SetGpr(op.rd, SExt(ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetType<s32>())));
}
void PPUTranslator::STD(ppu_opcode_t op)
{
WriteMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.ds << 2)) : m_ir->getInt64(op.ds << 2), GetGpr(op.rs));
Value* imm = m_ir->getInt64(op.ds << 2);
if (m_rel && m_rel->type == 57)
{
imm = m_ir->CreateAnd(SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>()), ~3);
m_rel = nullptr;
}
WriteMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetGpr(op.rs));
}
void PPUTranslator::STDU(ppu_opcode_t op)
{
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), m_ir->getInt64(op.ds << 2));
Value* imm = m_ir->getInt64(op.ds << 2);
if (m_rel && m_rel->type == 57)
{
imm = m_ir->CreateAnd(SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>()), ~3);
m_rel = nullptr;
}
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
WriteMemory(addr, GetGpr(op.rs));
SetGpr(op.ra, addr);
}
@ -3862,7 +4216,7 @@ void PPUTranslator::FCFID(ppu_opcode_t op)
void PPUTranslator::UNK(ppu_opcode_t op)
{
FlushRegisters();
Call(GetType<void>(), "__error", m_thread, m_ir->getInt64(m_current_addr), m_ir->getInt32(op.opcode))->setTailCallKind(llvm::CallInst::TCK_Tail);
Call(GetType<void>(), "__error", m_thread, GetAddr(), m_ir->getInt32(op.opcode))->setTailCallKind(llvm::CallInst::TCK_Tail);
m_ir->CreateRetVoid();
}
@ -4123,9 +4477,9 @@ Value* PPUTranslator::CheckTrapCondition(u32 to, Value* left, Value* right)
return trap_condition;
}
void PPUTranslator::Trap(u64 addr)
void PPUTranslator::Trap()
{
Call(GetType<void>(), "__trap", m_thread, m_ir->getInt64(m_current_addr))->setTailCallKind(llvm::CallInst::TCK_Tail);
Call(GetType<void>(), "__trap", m_thread, GetAddr())->setTailCallKind(llvm::CallInst::TCK_Tail);
m_ir->CreateRetVoid();
}

View File

@ -116,6 +116,9 @@ class PPUTranslator final //: public CPUTranslator
// PPU Module
const ppu_module& m_info;
// Relevant relocations
std::map<u64, const ppu_reloc*> m_relocs;
// Attributes for function calls which are "pure" and may be optimized away if their results are unused
const llvm::AttributeSet m_pure_attr;
@ -125,14 +128,23 @@ class PPUTranslator final //: public CPUTranslator
// LLVM function
llvm::Function* m_function;
// Function range
u64 m_start_addr, m_end_addr, m_current_addr;
llvm::MDNode* m_md_unlikely;
llvm::MDNode* m_md_likely;
// Current position-independent address
u64 m_addr = 0;
// Relocation info
const ppu_segment* m_reloc = nullptr;
// Set by instruction code after processing the relocation
const ppu_reloc* m_rel = nullptr;
/* Variables */
// Segments
std::vector<llvm::GlobalVariable*> m_segs;
// Memory base
llvm::GlobalVariable* m_base;
llvm::Value* m_base_loaded;
@ -179,6 +191,9 @@ class PPUTranslator final //: public CPUTranslator
#undef DEF_VALUE
public:
// Get current instruction address
llvm::Value* GetAddr(u64 _add = 0);
// Change integer size for integer or integer vector type (by 2^degree)
llvm::Type* ScaleType(llvm::Type*, s32 pow2 = 0);
@ -346,8 +361,8 @@ public:
// Check condition for trap instructions
llvm::Value* CheckTrapCondition(u32 to, llvm::Value* left, llvm::Value* right);
// Emit trap
void Trap(u64 addr);
// Emit trap for current address
void Trap();
// Get condition for branch instructions
llvm::Value* CheckBranchCondition(u32 bo, u32 bi);

View File

@ -109,7 +109,7 @@ error_code prx_load_module(std::string path, u64 flags, vm::ptr<sys_prx_load_mod
return CELL_PRX_ERROR_ILLEGAL_LIBRARY;
}
const auto prx = ppu_load_prx(obj, path.substr(path.find_last_of('/') + 1));
const auto prx = ppu_load_prx(obj, vfs::get(path));
if (!prx)
{