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. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4378 Signed-off-by: Simon Scherer <[email protected]> --- target/i386/tcg/fpu_helper.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c index b812125efa..49459b5bc1 100644 --- a/target/i386/tcg/fpu_helper.c +++ b/target/i386/tcg/fpu_helper.c @@ -532,6 +532,8 @@ void helper_fcom_ST0_FT0(CPUX86State *env) 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 &= ~0x0200; merge_exception_flags(env, old_flags); } @@ -542,6 +544,8 @@ void helper_fucom_ST0_FT0(CPUX86State *env) 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 &= ~0x0200; merge_exception_flags(env, old_flags); } @@ -556,6 +560,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); } @@ -568,6 +574,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.53.0
