From 1c3d35213ce29f0b23a0e98e9202bd1e26e3e628 Mon Sep 17 00:00:00 2001 From: Yang Liu Date: Fri, 30 Oct 2026 13:48:10 +0800 Subject: [PATCH 1/2] [ARM64_DYNAREC] Fixed YMM upper half lost with VPCLMULQDQ fallback native_pclmul_y() reads the Ex operand's upper 128 bits from emu->ymm[ed], but the handler used sse_forget_reg() for Ex, which only marks xmm_used. The upper half was considered dead, so loop merge points skipped materializing its pending zero. Use sse_reflect_reg() like for Vx. --- src/dynarec/arm64/dynarec_arm64_avx_66_0f3a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dynarec/arm64/dynarec_arm64_avx_66_0f3a.c b/src/dynarec/arm64/dynarec_arm64_avx_66_0f3a.c index e445260fd9..8a169cb8dd 100644 --- a/src/dynarec/arm64/dynarec_arm64_avx_66_0f3a.c +++ b/src/dynarec/arm64/dynarec_arm64_avx_66_0f3a.c @@ -704,7 +704,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip MOV32w(x2, vex.v); // vx if(MODREG) { ed = (nextop&7)+(rex.b<<3); - sse_forget_reg(dyn, ninst, ed); + sse_reflect_reg(dyn, ninst, ed); MOV32w(x3, ed); } else { addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1); From b2d5751fbd15f325b4c7a107e84780074f06661b Mon Sep 17 00:00:00 2001 From: Yang Liu Date: Fri, 30 Oct 2026 15:44:40 +0800 Subject: [PATCH 2/2] [ARM64_DYNAREC] Fixed sse_forget_reg YMM handling --- src/dynarec/arm64/dynarec_arm64_avx_66_0f3a.c | 2 +- src/dynarec/arm64/dynarec_arm64_helper.c | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/dynarec/arm64/dynarec_arm64_avx_66_0f3a.c b/src/dynarec/arm64/dynarec_arm64_avx_66_0f3a.c index 8a169cb8dd..e445260fd9 100644 --- a/src/dynarec/arm64/dynarec_arm64_avx_66_0f3a.c +++ b/src/dynarec/arm64/dynarec_arm64_avx_66_0f3a.c @@ -704,7 +704,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip MOV32w(x2, vex.v); // vx if(MODREG) { ed = (nextop&7)+(rex.b<<3); - sse_reflect_reg(dyn, ninst, ed); + sse_forget_reg(dyn, ninst, ed); MOV32w(x3, ed); } else { addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1); diff --git a/src/dynarec/arm64/dynarec_arm64_helper.c b/src/dynarec/arm64/dynarec_arm64_helper.c index adfebf0c79..a27213db92 100644 --- a/src/dynarec/arm64/dynarec_arm64_helper.c +++ b/src/dynarec/arm64/dynarec_arm64_helper.c @@ -1559,10 +1559,13 @@ int sse_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a) void sse_forget_reg(dynarec_arm_t* dyn, int ninst, int a) { dyn->n.xmm_used |= 1<n.ssecache[a].v==-1) - return; - if(dyn->n.neoncache[dyn->n.ssecache[a].reg].t == NEON_CACHE_XMMW) { - VSTR128_U12(dyn->n.ssecache[a].reg, xEmu, offsetof(x64emu_t, xmm[a])); + dyn->n.ymm_used |= 1<n.ssecache[a].v!=-1) { + if(dyn->n.neoncache[dyn->n.ssecache[a].reg].t == NEON_CACHE_XMMW) { + VSTR128_U12(dyn->n.ssecache[a].reg, xEmu, offsetof(x64emu_t, xmm[a])); + } + fpu_free_reg(dyn, dyn->n.ssecache[a].reg); + dyn->n.ssecache[a].v = -1; } // YMM part too if(is_avx_zero_unset(dyn, ninst, a)) { @@ -1580,9 +1583,6 @@ void sse_forget_reg(dynarec_arm_t* dyn, int ninst, int a) fpu_free_reg(dyn, i); } - fpu_free_reg(dyn, dyn->n.ssecache[a].reg); - dyn->n.ssecache[a].v = -1; - return; } // purge the SSE cache for XMM0..XMM7 (to use before function native call) void sse_purge07cache(dynarec_arm_t* dyn, int ninst, int s1)