mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-11 09:18:40 +12:00
Merge branch 'master' into master
This commit is contained in:
commit
f7dd259ab4
5 changed files with 187 additions and 78 deletions
|
@ -1177,6 +1177,7 @@ bool ppu_module<lv2_obj>::analyse(u32 lib_toc, u32 entry, const u32 sec_end, con
|
||||||
func.size = 0x1C;
|
func.size = 0x1C;
|
||||||
func.blocks.emplace(func.addr, func.size);
|
func.blocks.emplace(func.addr, func.size);
|
||||||
func.attr += ppu_attr::known_size;
|
func.attr += ppu_attr::known_size;
|
||||||
|
known_functions.emplace(func.addr);
|
||||||
|
|
||||||
// Look for another imports to fill gaps (hack)
|
// Look for another imports to fill gaps (hack)
|
||||||
auto _p2 = _ptr + 7;
|
auto _p2 = _ptr + 7;
|
||||||
|
@ -1195,6 +1196,7 @@ bool ppu_module<lv2_obj>::analyse(u32 lib_toc, u32 entry, const u32 sec_end, con
|
||||||
next.size = 0x1C;
|
next.size = 0x1C;
|
||||||
next.blocks.emplace(next.addr, next.size);
|
next.blocks.emplace(next.addr, next.size);
|
||||||
next.attr += ppu_attr::known_size;
|
next.attr += ppu_attr::known_size;
|
||||||
|
known_functions.emplace(_p2.addr());
|
||||||
advance(_p2, p2, 7);
|
advance(_p2, p2, 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1213,9 +1215,8 @@ bool ppu_module<lv2_obj>::analyse(u32 lib_toc, u32 entry, const u32 sec_end, con
|
||||||
// Trampoline with TOC
|
// Trampoline with TOC
|
||||||
const u32 target = (ptr[3] << 16) + s16(ptr[4]);
|
const u32 target = (ptr[3] << 16) + s16(ptr[4]);
|
||||||
const u32 toc_add = (ptr[1] << 16) + s16(ptr[2]);
|
const u32 toc_add = (ptr[1] << 16) + s16(ptr[2]);
|
||||||
constexpr u32 func_size = 0x1C;
|
|
||||||
|
|
||||||
if (target >= start && target < end && verify_ref((_ptr + 3).addr()) && target - func.addr >= func_size)
|
if (target >= start && target < end && verify_ref((_ptr + 3).addr()))
|
||||||
{
|
{
|
||||||
auto& new_func = add_func(target, 0, func.addr);
|
auto& new_func = add_func(target, 0, func.addr);
|
||||||
|
|
||||||
|
@ -1774,8 +1775,23 @@ bool ppu_module<lv2_obj>::analyse(u32 lib_toc, u32 entry, const u32 sec_end, con
|
||||||
|
|
||||||
u32 per_instruction_bytes = 0;
|
u32 per_instruction_bytes = 0;
|
||||||
|
|
||||||
for (auto&& [_, func] : fmap)
|
// Iterate by address (fmap may grow)
|
||||||
|
for (u32 addr_next = start; addr_next != end;)
|
||||||
{
|
{
|
||||||
|
// Get next iterator
|
||||||
|
const auto it = fmap.lower_bound(addr_next);
|
||||||
|
|
||||||
|
if (it == fmap.end())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save next function address as is as of this moment (ignoring added functions)
|
||||||
|
const auto it_next = std::next(it);
|
||||||
|
addr_next = it_next == fmap.end() ? end : it_next->first;
|
||||||
|
|
||||||
|
const ppu_function_ext& func = it->second;
|
||||||
|
|
||||||
if (func.attr & ppu_attr::no_size && entry)
|
if (func.attr & ppu_attr::no_size && entry)
|
||||||
{
|
{
|
||||||
// Disabled for PRX for now
|
// Disabled for PRX for now
|
||||||
|
@ -1793,6 +1809,7 @@ bool ppu_module<lv2_obj>::analyse(u32 lib_toc, u32 entry, const u32 sec_end, con
|
||||||
}
|
}
|
||||||
|
|
||||||
per_instruction_bytes += utils::sub_saturate<u32>(lim, func.addr);
|
per_instruction_bytes += utils::sub_saturate<u32>(lim, func.addr);
|
||||||
|
addr_next = std::max<u32>(addr_next, lim);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1814,7 +1831,7 @@ bool ppu_module<lv2_obj>::analyse(u32 lib_toc, u32 entry, const u32 sec_end, con
|
||||||
block.addr = addr;
|
block.addr = addr;
|
||||||
block.size = size;
|
block.size = size;
|
||||||
block.toc = func.toc;
|
block.toc = func.toc;
|
||||||
ppu_log.trace("Block __0x%x added (func=0x%x, size=0x%x, toc=0x%x)", block.addr, _, block.size, block.toc);
|
ppu_log.trace("Block __0x%x added (func=0x%x, size=0x%x, toc=0x%x)", block.addr, it->first, block.size, block.toc);
|
||||||
|
|
||||||
if (!entry && !sec_end)
|
if (!entry && !sec_end)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1652,7 +1652,7 @@ public:
|
||||||
u32 elements;
|
u32 elements;
|
||||||
u32 dwords;
|
u32 dwords;
|
||||||
|
|
||||||
if (m_use_avx512 && g_cfg.core.full_width_avx512)
|
if (m_use_avx512)
|
||||||
{
|
{
|
||||||
stride = 64;
|
stride = 64;
|
||||||
elements = 16;
|
elements = 16;
|
||||||
|
@ -1677,6 +1677,87 @@ public:
|
||||||
|
|
||||||
llvm::Value* acc = nullptr;
|
llvm::Value* acc = nullptr;
|
||||||
|
|
||||||
|
// Use a 512bit simple checksum to verify integrity if size is atleast 512b * 3
|
||||||
|
// This code uses a 512bit vector for all hardware to ensure behavior matches.
|
||||||
|
// The checksum path is still faster even on narrow hardware.
|
||||||
|
if ((end - starta) >= 192 && !g_cfg.core.precise_spu_verification)
|
||||||
|
{
|
||||||
|
for (u32 j = starta; j < end; j += 64)
|
||||||
|
{
|
||||||
|
int indices[16];
|
||||||
|
bool holes = false;
|
||||||
|
bool data = false;
|
||||||
|
|
||||||
|
for (u32 i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
const u32 k = j + i * 4;
|
||||||
|
|
||||||
|
if (k < start || k >= end || !func.data[(k - start) / 4])
|
||||||
|
{
|
||||||
|
indices[i] = 16;
|
||||||
|
holes = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
indices[i] = i;
|
||||||
|
data = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data)
|
||||||
|
{
|
||||||
|
// Skip full-sized holes
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::Value* vls = nullptr;
|
||||||
|
|
||||||
|
// Load unaligned code block from LS
|
||||||
|
vls = m_ir->CreateAlignedLoad(get_type<u32[16]>(), _ptr<u32[16]>(data_addr, j - starta), llvm::MaybeAlign{4});
|
||||||
|
|
||||||
|
// Mask if necessary
|
||||||
|
if (holes)
|
||||||
|
{
|
||||||
|
vls = m_ir->CreateShuffleVector(vls, ConstantAggregateZero::get(vls->getType()), llvm::ArrayRef(indices, 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
acc = acc ? m_ir->CreateAdd(acc, vls) : vls;
|
||||||
|
check_iterations++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the checksum
|
||||||
|
u32 checksum[16] = {0};
|
||||||
|
|
||||||
|
for (u32 j = 0; j < func.data.size(); j += 16) // Process 16 elements per iteration
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
if (j + i < func.data.size())
|
||||||
|
{
|
||||||
|
checksum[i] += func.data[j + i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* const_vector = ConstantDataVector::get(m_context, llvm::ArrayRef(checksum, 16));
|
||||||
|
acc = m_ir->CreateXor(acc, const_vector);
|
||||||
|
|
||||||
|
// Pattern for PTEST
|
||||||
|
acc = m_ir->CreateBitCast(acc, get_type<u64[8]>());
|
||||||
|
|
||||||
|
llvm::Value* elem = m_ir->CreateExtractElement(acc, u64{0});
|
||||||
|
|
||||||
|
for (u32 i = 1; i < 8; i++)
|
||||||
|
{
|
||||||
|
elem = m_ir->CreateOr(elem, m_ir->CreateExtractElement(acc, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare result with zero
|
||||||
|
const auto cond = m_ir->CreateICmpNE(elem, m_ir->getInt64(0));
|
||||||
|
m_ir->CreateCondBr(cond, label_diff, label_body, m_md_unlikely);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
for (u32 j = starta; j < end; j += stride)
|
for (u32 j = starta; j < end; j += stride)
|
||||||
{
|
{
|
||||||
int indices[16];
|
int indices[16];
|
||||||
|
@ -1708,7 +1789,7 @@ public:
|
||||||
llvm::Value* vls = nullptr;
|
llvm::Value* vls = nullptr;
|
||||||
|
|
||||||
// Load unaligned code block from LS
|
// Load unaligned code block from LS
|
||||||
if (m_use_avx512 && g_cfg.core.full_width_avx512)
|
if (m_use_avx512)
|
||||||
{
|
{
|
||||||
vls = m_ir->CreateAlignedLoad(get_type<u32[16]>(), _ptr<u32[16]>(data_addr, j - starta), llvm::MaybeAlign{4});
|
vls = m_ir->CreateAlignedLoad(get_type<u32[16]>(), _ptr<u32[16]>(data_addr, j - starta), llvm::MaybeAlign{4});
|
||||||
}
|
}
|
||||||
|
@ -1740,9 +1821,8 @@ public:
|
||||||
acc = acc ? m_ir->CreateOr(acc, vls) : vls;
|
acc = acc ? m_ir->CreateOr(acc, vls) : vls;
|
||||||
check_iterations++;
|
check_iterations++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pattern for PTEST
|
// Pattern for PTEST
|
||||||
if (m_use_avx512 && g_cfg.core.full_width_avx512)
|
if (m_use_avx512)
|
||||||
{
|
{
|
||||||
acc = m_ir->CreateBitCast(acc, get_type<u64[8]>());
|
acc = m_ir->CreateBitCast(acc, get_type<u64[8]>());
|
||||||
}
|
}
|
||||||
|
@ -1766,6 +1846,7 @@ public:
|
||||||
const auto cond = m_ir->CreateICmpNE(elem, m_ir->getInt64(0));
|
const auto cond = m_ir->CreateICmpNE(elem, m_ir->getInt64(0));
|
||||||
m_ir->CreateCondBr(cond, label_diff, label_body, m_md_unlikely);
|
m_ir->CreateCondBr(cond, label_diff, label_body, m_md_unlikely);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Increase block counter with statistics
|
// Increase block counter with statistics
|
||||||
m_ir->SetInsertPoint(label_body);
|
m_ir->SetInsertPoint(label_body);
|
||||||
|
|
|
@ -147,7 +147,7 @@ u64 convert_to_timebased_time(u64 time)
|
||||||
|
|
||||||
u64 get_timebased_time()
|
u64 get_timebased_time()
|
||||||
{
|
{
|
||||||
if (0) if (u64 freq = utils::get_tsc_freq())
|
if (u64 freq = utils::get_tsc_freq())
|
||||||
{
|
{
|
||||||
const u64 tsc = utils::get_tsc();
|
const u64 tsc = utils::get_tsc();
|
||||||
|
|
||||||
|
@ -207,7 +207,7 @@ void initialize_timebased_time(u64 timebased_init, bool reset)
|
||||||
// Returns some relative time in microseconds, don't change this fact
|
// Returns some relative time in microseconds, don't change this fact
|
||||||
u64 get_system_time()
|
u64 get_system_time()
|
||||||
{
|
{
|
||||||
if (0) if (u64 freq = utils::get_tsc_freq())
|
if (u64 freq = utils::get_tsc_freq())
|
||||||
{
|
{
|
||||||
const u64 tsc = utils::get_tsc();
|
const u64 tsc = utils::get_tsc();
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ struct cfg_root : cfg::node
|
||||||
cfg::_enum<xfloat_accuracy> spu_xfloat_accuracy{ this, "XFloat Accuracy", xfloat_accuracy::approximate, false };
|
cfg::_enum<xfloat_accuracy> spu_xfloat_accuracy{ this, "XFloat Accuracy", xfloat_accuracy::approximate, false };
|
||||||
cfg::_int<-1, 14> ppu_128_reservations_loop_max_length{ this, "Accurate PPU 128-byte Reservation Op Max Length", 0, true }; // -1: Always accurate, 0: Never accurate, 1-14: max accurate loop length
|
cfg::_int<-1, 14> ppu_128_reservations_loop_max_length{ this, "Accurate PPU 128-byte Reservation Op Max Length", 0, true }; // -1: Always accurate, 0: Never accurate, 1-14: max accurate loop length
|
||||||
cfg::_int<-64, 64> stub_ppu_traps{ this, "Stub PPU Traps", 0, true }; // Hack, skip PPU traps for rare cases where the trap is continueable (specify relative instructions to skip)
|
cfg::_int<-64, 64> stub_ppu_traps{ this, "Stub PPU Traps", 0, true }; // Hack, skip PPU traps for rare cases where the trap is continueable (specify relative instructions to skip)
|
||||||
cfg::_bool full_width_avx512{ this, "Full Width AVX-512", true };
|
cfg::_bool precise_spu_verification{ this, "Precise SPU Verification", false }; // Disables use of xorsum based spu verification if enabled.
|
||||||
cfg::_bool ppu_llvm_nj_fixup{ this, "PPU LLVM Java Mode Handling", true }; // Partially respect current Java Mode for alti-vec ops by PPU LLVM
|
cfg::_bool ppu_llvm_nj_fixup{ this, "PPU LLVM Java Mode Handling", true }; // Partially respect current Java Mode for alti-vec ops by PPU LLVM
|
||||||
cfg::_bool use_accurate_dfma{ this, "Use Accurate DFMA", true }; // Enable accurate double-precision FMA for CPUs which do not support it natively
|
cfg::_bool use_accurate_dfma{ this, "Use Accurate DFMA", true }; // Enable accurate double-precision FMA for CPUs which do not support it natively
|
||||||
cfg::_bool ppu_set_sat_bit{ this, "PPU Set Saturation Bit", false }; // Accuracy. If unset, completely disable saturation flag handling.
|
cfg::_bool ppu_set_sat_bit{ this, "PPU Set Saturation Bit", false }; // Accuracy. If unset, completely disable saturation flag handling.
|
||||||
|
|
|
@ -524,7 +524,7 @@ std::string utils::get_system_info()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fmt::append(result, " | TSC: Bad");
|
fmt::append(result, " | TSC: Disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_avx())
|
if (has_avx())
|
||||||
|
@ -772,15 +772,26 @@ static const bool s_tsc_freq_evaluated = []() -> bool
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!utils::has_invariant_tsc())
|
if (!utils::has_invariant_tsc())
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (utils::get_cpu_brand().find("Ryzen") != umax)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
LARGE_INTEGER freq;
|
LARGE_INTEGER freq;
|
||||||
if (!QueryPerformanceFrequency(&freq))
|
if (!QueryPerformanceFrequency(&freq))
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (freq.QuadPart <= 9'999'999)
|
if (freq.QuadPart <= 9'999'999)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const ullong timer_freq = freq.QuadPart;
|
const ullong timer_freq = freq.QuadPart;
|
||||||
#else
|
#else
|
||||||
|
@ -880,7 +891,7 @@ static const bool s_tsc_freq_evaluated = []() -> bool
|
||||||
return round_tsc(res, utils::mul_saturate<u64>(utils::add_saturate<u64>(rdtsc_diff[0], rdtsc_diff[1]), utils::aligned_div(timer_freq, timer_data[1] - timer_data[0])));
|
return round_tsc(res, utils::mul_saturate<u64>(utils::add_saturate<u64>(rdtsc_diff[0], rdtsc_diff[1]), utils::aligned_div(timer_freq, timer_data[1] - timer_data[0])));
|
||||||
}();
|
}();
|
||||||
|
|
||||||
atomic_storage<u64>::release(utils::s_tsc_freq, cal_tsc);
|
atomic_storage<u64>::store(utils::s_tsc_freq, cal_tsc);
|
||||||
return true;
|
return true;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue