[PATCH v3] target/i386: Clear C1 for FCOM/FUCOM/FICOM

Simon Scherer posted 1 patch 3 weeks, 3 days ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20260902135705.261863-1-scherer.simon89@gmail.com
Maintainers: Paolo Bonzini <pbonzini@redhat.com>, Richard Henderson <richard.henderson@linaro.org>
target/i386/tcg/fpu_helper.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
[PATCH v3] target/i386: Clear C1 for FCOM/FUCOM/FICOM
Posted by Simon Scherer 3 weeks, 3 days ago
The SDM specifies that FCOM/FCOMP/FCOMPP/FUCOM/FUCOMP/FUCOMPP/FICOM/FICOMP
unconditionally clear C1 in the FPU status word, regardless of the
comparison result.

helper_fcom_ST0_FT0/helper_fucom_ST0_FT0 only cleared C3, C2, C0 (mask
0x4500) before OR-ing in the comparison result, leaving C1 (bit 9) at
whatever value it already had. FICOM/FICOMP dispatch through the same
helpers after converting their integer operand, so they inherited the
same bug.

This patch folds the C1 clear into the existing fpus mask
for both helpers, since fcom_ccval never sets bit 9 itself.

The SDM also lists "C1 Set to 0" for FCOMI/FCOMIP/FUCOMI/FUCOMIP.
Testing against real x86-64 hardware shows this instruction group
does not actually clear C1, unlike FCOM/FUCOM/FICOM. QEMU's
existing behavior for those four is already correct, so
they are intentionally left unchanged.

Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4378
Signed-off-by: Simon Scherer <scherer.simon89@gmail.com>
---
v3: drop the C1 clear in helper_fcomi_ST0_FT0/helper_fucomi_ST0_FT0.
    Hardware testing shows FCOMI/FCOMIP/FUCOMI/FUCOMIP do not actually
    clear C1, unlike FCOM/FUCOM/FICOM.
v2: merge the C1 clear into the existing fpus mask for
    fcom_ST0_FT0/fucom_ST0_FT0 (Richard Henderson)

Signed-off-by: Simon Scherer <scherer.simon89@gmail.com>

 target/i386/tcg/fpu_helper.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c
index b812125efa..34670a1c2b 100644
--- a/target/i386/tcg/fpu_helper.c
+++ b/target/i386/tcg/fpu_helper.c
@@ -531,7 +531,8 @@ void helper_fcom_ST0_FT0(CPUX86State *env)
     FloatRelation ret;
 
     ret = floatx80_compare(ST0, FT0, &env->fp_status);
-    env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1];
+    /* C1 is unconditionally cleared to 0 */
+    env->fpus = (env->fpus & ~0x4700) | fcom_ccval[ret + 1];
     merge_exception_flags(env, old_flags);
 }
 
@@ -541,7 +542,8 @@ void helper_fucom_ST0_FT0(CPUX86State *env)
     FloatRelation ret;
 
     ret = floatx80_compare_quiet(ST0, FT0, &env->fp_status);
-    env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1];
+    /* C1 is unconditionally cleared to 0 */
+    env->fpus = (env->fpus & ~0x4700) | fcom_ccval[ret + 1];
     merge_exception_flags(env, old_flags);
 }
 
-- 
2.53.0