svn commit: r367115 - in stable/12/sys: amd64/ia32 i386/i386

Konstantin Belousov kib at FreeBSD.org
Wed Oct 28 21:01:01 UTC 2020


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


More information about the svn-src-all mailing list