[dynarmic] fix pre-SSE4.1 having errors on CMHI/CMLO, fix extra nuisances and add INTERP testcase (#4025)
Some checks are pending
tx-src / sources (push) Waiting to run
Check Strings / check-strings (push) Waiting to run

does a bit of code dedup
fixes pre-SSE4.1 having horrific CMHI/CMLO

Signed-off-by: lizzie <lizzie@eden-emu.dev>

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4025
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
This commit is contained in:
lizzie 2026-06-03 22:53:21 +02:00 committed by crueter
parent f729dbb3c3
commit ad9af25027
No known key found for this signature in database
GPG key ID: 425ACD2D4830EBC6
6 changed files with 158 additions and 115 deletions

View file

@ -2587,11 +2587,11 @@ TEST_CASE("A64: Manual Vector Min/Max U64 (Optimizer Test)", "[a64]") {
// MaxU64 pattern: (a > b) ? a : b
code.CMHI(V2.D2(), V0.D2(), V1.D2()); // V2 = Mask (A > B)
code.BSL(V2.B16(), V0.B16(), V1.B16()); // V2 = Resul
code.BSL(V2.B16(), V0.B16(), V1.B16()); // V2 = Result
// MinU64 pattern: (a > b) ? b : a
code.CMHI(V3.D2(), V0.D2(), V1.D2()); // V3 = Mask (A > B)
code.BSL(V3.B16(), V1.B16(), V0.B16()); // V3 = Resul
code.BSL(V3.B16(), V1.B16(), V0.B16()); // V3 = Result
jit.SetPC(0);
jit.SetVector(0, {100, 20});
@ -2603,3 +2603,32 @@ TEST_CASE("A64: Manual Vector Min/Max U64 (Optimizer Test)", "[a64]") {
CHECK(jit.GetVector(2) == Vector{100, 200});
CHECK(jit.GetVector(3) == Vector{50, 20});
}
TEST_CASE("A64: Rounding", "[a64]") {
A64TestEnv env;
A64::UserConfig jit_user_config{};
jit_user_config.callbacks = &env;
A64::Jit jit{jit_user_config};
oaknut::VectorCodeGenerator code{env.code_mem, nullptr};
code.FRINTN(V1.S4(), V0.S4()); // ToNearest_TieEven
code.FRINTM(V2.S4(), V0.S4()); // TowardsMinusInfinity
code.FRINTP(V3.S4(), V0.S4()); // TowardsPlusInfinity
code.FRINTZ(V4.S4(), V0.S4()); // TowardsZero
code.FRINTA(V5.S4(), V0.S4()); // ToNearest_TieAwayFromZero
code.FRINTX(V6.S4(), V0.S4()); // ToNearest_TieAwayFromZero
jit.SetPC(0);
jit.SetVector(0, {0x4001e17c4001e17c, 0x4001e17c4001e17c});
env.ticks_left = env.code_mem.size();
CheckedRun([&]() { jit.Run(); });
CHECK(jit.GetVector(0) == Vector{0x4001e17c4001e17c, 0x4001e17c4001e17c});
CHECK(jit.GetVector(1) == Vector{0x4000000040000000, 0x4000000040000000});
CHECK(jit.GetVector(2) == Vector{0x4000000040000000, 0x4000000040000000});
CHECK(jit.GetVector(3) == Vector{0x4040000040400000, 0x4040000040400000});
CHECK(jit.GetVector(4) == Vector{0x4000000040000000, 0x4000000040000000});
CHECK(jit.GetVector(5) == Vector{0x4000000040000000, 0x4000000040000000});
CHECK(jit.GetVector(6) == Vector{0x4000000040000000, 0x4000000040000000});
}

View file

@ -17,24 +17,19 @@ using Vector = Dynarmic::A64::Vector;
class A64TestEnv : public Dynarmic::A64::UserCallbacks {
public:
u64 ticks_left = 0;
bool code_mem_modified_by_guest = false;
u64 code_mem_start_address = 0;
std::vector<u32> code_mem;
ankerl::unordered_dense::map<u64, u8> modified_memory;
std::vector<std::string> interrupts;
std::vector<u32> code_mem;
u64 ticks_left = 0;
u64 code_mem_start_address = 0;
bool code_mem_modified_by_guest = false;
bool IsInCodeMem(u64 vaddr) const {
return vaddr >= code_mem_start_address && vaddr < code_mem_start_address + code_mem.size() * 4;
}
std::optional<std::uint32_t> MemoryReadCode(u64 vaddr) override {
if (!IsInCodeMem(vaddr)) {
if (!IsInCodeMem(vaddr))
return 0x14000000; // B .
}
const size_t index = (vaddr - code_mem_start_address) / 4;
return code_mem[index];
}
@ -43,10 +38,9 @@ public:
if (IsInCodeMem(vaddr)) {
return reinterpret_cast<u8*>(code_mem.data())[vaddr - code_mem_start_address];
}
if (auto iter = modified_memory.find(vaddr); iter != modified_memory.end()) {
return iter->second;
}
return static_cast<u8>(vaddr);
if (auto const it = modified_memory.find(vaddr); it != modified_memory.end())
return it->second;
return u8(vaddr);
}
std::uint16_t MemoryRead16(u64 vaddr) override {
return u16(MemoryRead8(vaddr)) | u16(MemoryRead8(vaddr + 1)) << 8;
@ -68,16 +62,16 @@ public:
modified_memory[vaddr] = value;
}
void MemoryWrite16(u64 vaddr, std::uint16_t value) override {
MemoryWrite8(vaddr, static_cast<u8>(value));
MemoryWrite8(vaddr + 1, static_cast<u8>(value >> 8));
MemoryWrite8(vaddr, u8(value));
MemoryWrite8(vaddr + 1, u8(value >> 8));
}
void MemoryWrite32(u64 vaddr, std::uint32_t value) override {
MemoryWrite16(vaddr, static_cast<u16>(value));
MemoryWrite16(vaddr + 2, static_cast<u16>(value >> 16));
MemoryWrite16(vaddr, u16(value));
MemoryWrite16(vaddr + 2, u16(value >> 16));
}
void MemoryWrite64(u64 vaddr, std::uint64_t value) override {
MemoryWrite32(vaddr, static_cast<u32>(value));
MemoryWrite32(vaddr + 4, static_cast<u32>(value >> 32));
MemoryWrite32(vaddr, u32(value));
MemoryWrite32(vaddr + 4, u32(value >> 32));
}
void MemoryWrite128(u64 vaddr, Vector value) override {
MemoryWrite64(vaddr, value[0]);
@ -139,12 +133,12 @@ public:
template<typename T>
T read(u64 vaddr) {
T value;
memcpy(&value, backing_memory + vaddr, sizeof(T));
std::memcpy(&value, backing_memory + vaddr, sizeof(T));
return value;
}
template<typename T>
void write(u64 vaddr, const T& value) {
memcpy(backing_memory + vaddr, &value, sizeof(T));
std::memcpy(backing_memory + vaddr, &value, sizeof(T));
}
std::optional<std::uint32_t> MemoryReadCode(u64 vaddr) override {