Author: kib
Date: Wed Oct 28 21:01:00 2020
New Revision: 367115
URL: https://svnweb.freebsd.org/changeset/base/367115

Log:
  MFC r366904:
  Improve FPU Tag Word reconstruction on i386 to indicate register states.
  
  PR:   250454

Modified:
  stable/12/sys/amd64/ia32/ia32_reg.c
  stable/12/sys/i386/i386/npx.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/amd64/ia32/ia32_reg.c
==============================================================================
--- stable/12/sys/amd64/ia32/ia32_reg.c Wed Oct 28 20:22:20 2020        
(r367114)
+++ stable/12/sys/amd64/ia32/ia32_reg.c Wed Oct 28 21:01:00 2020        
(r367115)
@@ -146,7 +146,11 @@ fill_fpregs32(struct thread *td, struct fpreg32 *regs)
        struct save87 *sv_87;
        struct env87 *penv_87;
        struct envxmm *penv_xmm;
-       int i;
+       struct fpacc87 *fx_reg;
+       int i, st;
+       uint64_t mantissa;
+       uint16_t tw, exp;
+       uint8_t ab_tw;
 
        bzero(regs, sizeof(*regs));
        sv_87 = (struct save87 *)regs;
@@ -172,13 +176,39 @@ fill_fpregs32(struct thread *td, struct fpreg32 *regs)
        /* Entry into the kernel always sets TF_HASSEGS */
        penv_87->en_fos = td->td_frame->tf_ds;
 
-       /* FPU registers and tags */
-       penv_87->en_tw = 0xffff;
-       for (i = 0; i < 8; ++i) {
-               sv_87->sv_ac[i] = sv_fpu->sv_fp[i].fp_acc;
-               if ((penv_xmm->en_tw & (1 << i)) != 0)
-                       penv_87->en_tw &= ~(3 << i * 2);
+       /*
+        * FPU registers and tags.
+        * For ST(i), i = fpu_reg - top; we start with fpu_reg=7.
+        */
+       st = 7 - ((penv_xmm->en_sw >> 11) & 7);
+       ab_tw = penv_xmm->en_tw;
+       tw = 0;
+       for (i = 0x80; i != 0; i >>= 1) {
+               sv_87->sv_ac[st] = sv_fpu->sv_fp[st].fp_acc;
+               tw <<= 2;
+               if ((ab_tw & i) != 0) {
+                       /* Non-empty - we need to check ST(i) */
+                       fx_reg = &sv_fpu->sv_fp[st].fp_acc;
+                       /* The first 64 bits contain the mantissa. */
+                       mantissa = *((uint64_t *)fx_reg->fp_bytes);
+                       /*
+                        * The final 16 bits contain the sign bit and the 
exponent.
+                        * Mask the sign bit since it is of no consequence to 
these
+                        * tests.
+                        */
+                       exp = *((uint16_t *)&fx_reg->fp_bytes[8]) & 0x7fff;
+                       if (exp == 0) {
+                               if (mantissa == 0)
+                                       tw |= 1; /* Zero */
+                               else
+                                       tw |= 2; /* Denormal */
+                       } else if (exp == 0x7fff)
+                               tw |= 2; /* Infinity or NaN */
+               } else
+                       tw |= 3; /* Empty */
+               st = (st - 1) & 7;
        }
+       penv_87->en_tw = tw;
 
        return (0);
 }

Modified: stable/12/sys/i386/i386/npx.c
==============================================================================
--- stable/12/sys/i386/i386/npx.c       Wed Oct 28 20:22:20 2020        
(r367114)
+++ stable/12/sys/i386/i386/npx.c       Wed Oct 28 21:01:00 2020        
(r367115)
@@ -1149,7 +1149,11 @@ npx_fill_fpregs_xmm1(struct savexmm *sv_xmm, struct sa
 {
        struct env87 *penv_87;
        struct envxmm *penv_xmm;
-       int i;
+       struct fpacc87 *fx_reg;
+       int i, st;
+       uint64_t mantissa;
+       uint16_t tw, exp;
+       uint8_t ab_tw;
 
        penv_87 = &sv_87->sv_env;
        penv_xmm = &sv_xmm->sv_env;
@@ -1163,14 +1167,39 @@ npx_fill_fpregs_xmm1(struct savexmm *sv_xmm, struct sa
        penv_87->en_foo = penv_xmm->en_foo;
        penv_87->en_fos = penv_xmm->en_fos;
 
-       /* FPU registers and tags */
-       penv_87->en_tw = 0xffff;
-       for (i = 0; i < 8; ++i) {
-               sv_87->sv_ac[i] = sv_xmm->sv_fp[i].fp_acc;
-               if ((penv_xmm->en_tw & (1 << i)) != 0)
-                       /* zero and special are set as valid */
-                       penv_87->en_tw &= ~(3 << i * 2);
+       /*
+        * FPU registers and tags.
+        * For ST(i), i = fpu_reg - top; we start with fpu_reg=7.
+        */
+       st = 7 - ((penv_xmm->en_sw >> 11) & 7);
+       ab_tw = penv_xmm->en_tw;
+       tw = 0;
+       for (i = 0x80; i != 0; i >>= 1) {
+               sv_87->sv_ac[st] = sv_xmm->sv_fp[st].fp_acc;
+               tw <<= 2;
+               if (ab_tw & i) {
+                       /* Non-empty - we need to check ST(i) */
+                       fx_reg = &sv_xmm->sv_fp[st].fp_acc;
+                       /* The first 64 bits contain the mantissa. */
+                       mantissa = *((uint64_t *)fx_reg->fp_bytes);
+                       /*
+                        * The final 16 bits contain the sign bit and the 
exponent.
+                        * Mask the sign bit since it is of no consequence to 
these
+                        * tests.
+                        */
+                       exp = *((uint16_t *)&fx_reg->fp_bytes[8]) & 0x7fff;
+                       if (exp == 0) {
+                               if (mantissa == 0)
+                                       tw |= 1; /* Zero */
+                               else
+                                       tw |= 2; /* Denormal */
+                       } else if (exp == 0x7fff)
+                               tw |= 2; /* Infinity or NaN */
+               } else
+                       tw |= 3; /* Empty */
+               st = (st - 1) & 7;
        }
+       penv_87->en_tw = tw;
 }
 
 void
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to