The GDB stub was returning a hardcoded 0 for the x87 FPU tag word register (ftag). Factor out cpu_compute_fptag() helper. Simplify a little bit the code by dropping unnecessary CPU_LDoubleU reinterpretation, building the value 0..7, avoiding signed-shifting.
Signed-off-by: Marc-André Lureau <[email protected]> --- target/i386/cpu.c | 28 ++++++++++++++++++++++++++++ target/i386/cpu.h | 9 +++++++++ target/i386/gdbstub.c | 2 +- target/i386/tcg/fpu_helper.c | 24 ++---------------------- 4 files changed, 40 insertions(+), 23 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 37732b65e408..2f5ea4e51715 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -9372,6 +9372,34 @@ static bool cpuid_has_xsave_feature(CPUX86State *env, const ExtSaveArea *esa) return false; } +uint16_t cpu_compute_fptag(CPUX86State *env) +{ + uint16_t fptag = 0; + + for (int i = 0; i < 8; i++) { + unsigned tag; + + if (env->fptags[i]) { + tag = 3; /* empty */ + } else { + floatx80 f = env->fpregs[i].d; + uint16_t exponent = f.high & 0x7fff; + uint64_t mantissa = f.low; + + if (exponent == 0 && mantissa == 0) { + tag = 1; /* zero */ + } else if (exponent == 0 || exponent == 0x7fff || + !(mantissa & (1ULL << 63))) { + tag = 2; /* NaNs, infinity, denormal */ + } else { + tag = 0; /* valid */ + } + } + fptag |= tag << (2 * i); + } + return fptag; +} + static void x86_cpu_reset_hold(Object *obj, ResetType type) { CPUState *cs = CPU(obj); diff --git a/target/i386/cpu.h b/target/i386/cpu.h index e7a88074c071..116e28a59701 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -2989,6 +2989,15 @@ static inline void cpu_set_mxcsr(CPUX86State *env, uint32_t mxcsr) } } +/** + * cpu_compute_fptag - Compute the full 16-bit x87 FPU tag word. + * + * Reconstructs the 16-bit tag word from the fpregs and fptags arrays. + * Each of the 8 physical registers gets a 2-bit tag in bits [2*i+1 : 2*i]: + * 0 = valid, 1 = zero, 2 = special (NaN/Inf/denormal), 3 = empty. + */ +uint16_t cpu_compute_fptag(CPUX86State *env); + static inline void cpu_set_fpuc(CPUX86State *env, uint16_t fpuc) { env->fpuc = fpuc; diff --git a/target/i386/gdbstub.c b/target/i386/gdbstub.c index c0cde26d978c..420ce845eeae 100644 --- a/target/i386/gdbstub.c +++ b/target/i386/gdbstub.c @@ -186,7 +186,7 @@ int x86_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) return gdb_get_reg32(mem_buf, (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11); case IDX_FP_REGS + 10: - return gdb_get_reg32(mem_buf, 0); /* ftag */ + return gdb_get_reg32(mem_buf, cpu_compute_fptag(env)); case IDX_FP_REGS + 11: return gdb_get_reg32(mem_buf, 0); /* fiseg */ case IDX_FP_REGS + 12: diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c index 4bbac996326e..81ae3d8f3d0f 100644 --- a/target/i386/tcg/fpu_helper.c +++ b/target/i386/tcg/fpu_helper.c @@ -2459,30 +2459,10 @@ void helper_fxam_ST0(CPUX86State *env) static void do_fstenv(X86Access *ac, target_ulong ptr, int data32) { CPUX86State *env = ac->env; - int fpus, fptag, exp, i; - uint64_t mant; - CPU_LDoubleU tmp; + int fpus, fptag; fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; - fptag = 0; - for (i = 7; i >= 0; i--) { - fptag <<= 2; - if (env->fptags[i]) { - fptag |= 3; - } else { - tmp.d = env->fpregs[i].d; - exp = EXPD(tmp); - mant = MANTD(tmp); - if (exp == 0 && mant == 0) { - /* zero */ - fptag |= 1; - } else if (exp == 0 || exp == MAXEXPD - || (mant & (1LL << 63)) == 0) { - /* NaNs, infinity, denormal */ - fptag |= 2; - } - } - } + fptag = cpu_compute_fptag(env); if (data32) { /* 32 bit */ access_stl(ac, ptr, env->fpuc); -- 2.56.0.116.g6de20f6092dc
