From: Simon Scherer <[email protected]> The SDM specifies that FCOM/FCOMP/FCOMPP/FUCOM/FUCOMP/FUCOMPP/FICOM/FICOMP/ FCOMI/FCOMIP/FUCOMI/FUCOMIP 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. helper_fcomi_ST0_FT0/helper_fucomi_ST0_FT0 never touched the FPU status word at all, so C1 was left untouched by those too. This patch clears C1 explicitly in all four helpers, adding the clear into the existing fpus mask for fcom/fucom since fcom_ccval never sets bit 9. For fcomi/fucomi add a new separate clear. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4378 Signed-off-by: Simon Scherer <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Paolo Bonzini <[email protected]> --- target/i386/tcg/fpu_helper.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c index 32af8b79f4f..56fb94c957b 100644 --- a/target/i386/tcg/fpu_helper.c +++ b/target/i386/tcg/fpu_helper.c @@ -534,7 +534,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); } @@ -544,7 +545,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); } @@ -559,6 +561,8 @@ void helper_fcomi_ST0_FT0(CPUX86State *env) /* OF, SF, and AF are unconditionally cleared to 0 */ CC_SRC = fcomi_ccval[ret + 1]; CC_OP = CC_OP_EFLAGS; + /* C1 is unconditionally cleared to 0 */ + env->fpus &= ~0x0200; merge_exception_flags(env, old_flags); } @@ -571,6 +575,8 @@ void helper_fucomi_ST0_FT0(CPUX86State *env) /* OF, SF, and AF are unconditionally cleared to 0 */ CC_SRC = fcomi_ccval[ret + 1]; CC_OP = CC_OP_EFLAGS; + /* C1 is unconditionally cleared to 0 */ + env->fpus &= ~0x0200; merge_exception_flags(env, old_flags); } -- 2.55.0
